img2htm API Documentation
Turn images into production HTML with 1 API call
The img2htm API accepts an image file or URL and returns HTML, CSS, separated images, structured JSON and a quality report.
Get started
The img2htm API accepts an image file or URL and returns HTML, CSS, separated images, structured JSON and a quality report. First 50 preview calls per month are on us.
- Create account → Create a key in your dashboard
POST https://img2htm.com/api/v1/reconstructwithimage_file,image_urlorimage_file_b64.- Receive HTML, CSS, separated assets, structured JSON and a quality report in one response.
Easy to integrate
Examples for cURL, Node.js, Python, PHP, Ruby, Java, .NET and Swift.
HTML + CSS + JSON
One API call returns HTML, CSS, separated images, structured JSON and a quality report.
What is a credit?
One credit fully converts one image up to 15,000 vertical pixels. Longer images are automatically counted as several credits. Previews are free.
Authentication
Send your API key in the Authorization: Bearer header or the X-Api-Key header.
Authorization: Bearer i2h_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# or
X-Api-Key: i2h_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Sample code
curl -X POST https://img2htm.com/api/v1/reconstruct \ -H "Authorization: Bearer i2h_your_api_key" \ -F "image_file=@product-page.jpg" \ -F "mode=full" \ -F "format=json"
import fs from 'node:fs';
const form = new FormData();
form.append('image_file', new Blob([fs.readFileSync('product-page.jpg')]), 'product-page.jpg');
form.append('mode', 'full');
const res = await fetch('https://img2htm.com/api/v1/reconstruct', {
method: 'POST',
headers: { Authorization: 'Bearer i2h_your_api_key' },
body: form,
});
const job = await res.json();
console.log(job.status, job.urls.html);import requests
with open('product-page.jpg', 'rb') as f:
r = requests.post(
'https://img2htm.com/api/v1/reconstruct',
headers={'Authorization': 'Bearer i2h_your_api_key'},
files={'image_file': f},
data={'mode': 'full', 'format': 'json'},
timeout=600,
)
job = r.json()
print(job['status'], job['sections'], job['urls']['zip'])<?php
$ch = curl_init('https://img2htm.com/api/v1/reconstruct');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer i2h_your_api_key'],
CURLOPT_POSTFIELDS => [
'image_file' => new CURLFile('product-page.jpg'),
'mode' => 'full',
],
]);
$job = json_decode(curl_exec($ch), true);
file_put_contents('index.html', $job['html']);require 'net/http'
require 'json'
uri = URI('https://img2htm.com/api/v1/reconstruct')
req = Net::HTTP::Post.new(uri)
req['Authorization'] = 'Bearer i2h_your_api_key'
req.set_form([['image_file', File.open('product-page.jpg')], ['mode', 'full']], 'multipart/form-data')
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
job = JSON.parse(res.body)
puts job['status']HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://img2htm.com/api/v1/reconstruct"))
.header("Authorization", "Bearer i2h_your_api_key")
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(
"image_url=https://example.com/page.jpg&mode=full"))
.build();
HttpResponse<String> res = client.send(request, HttpResponse.BodyHandlers.ofString());
System.out.println(res.body());using var http = new HttpClient();
http.DefaultRequestHeaders.Authorization = new("Bearer", "i2h_your_api_key");
using var form = new MultipartFormDataContent();
form.Add(new ByteArrayContent(File.ReadAllBytes("product-page.jpg")), "image_file", "product-page.jpg");
form.Add(new StringContent("full"), "mode");
var res = await http.PostAsync("https://img2htm.com/api/v1/reconstruct", form);
Console.WriteLine(await res.Content.ReadAsStringAsync());var request = URLRequest(url: URL(string: "https://img2htm.com/api/v1/reconstruct")!)
request.httpMethod = "POST"
request.setValue("Bearer i2h_your_api_key", forHTTPHeaderField: "Authorization")
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.httpBody = "image_url=https://example.com/page.jpg&mode=full".data(using: .utf8)
let (data, _) = try await URLSession.shared.data(for: request)
print(String(data: data, encoding: .utf8)!) Output formats
format | Description |
|---|---|
json | Default. JSON object with html, css, content (structured sections + texts), assets (separated image URLs), quality and urls. |
html | Returns the reconstructed index.html document directly (text/html). |
zip | Streams a ZIP with index.html, styles.css, content.json, quality.json, sections/ and assets/. |
Response
{
"id": "3f9a1c2b7d4e6f80a1b2",
"status": "done",
"mode": "full",
"credits_used": 2,
"width": 860,
"height": 24000,
"sections": 16,
"quality": {
"text_accuracy": 97.4,
"visual_fidelity": 94.1,
"structure": 95.2,
"sections": 16,
"seconds": 41.8,
"provider": "anthropic:claude-sonnet-5",
"review": [],
"auto_pass": true
},
"urls": {
"html": "https://img2htm.com/api/v1/jobs/3f9a1c2b7d4e6f80a1b2/html",
"zip": "https://img2htm.com/en/convert/3f9a1c2b7d4e6f80a1b2/download",
"preview": "https://img2htm.com/en/convert/3f9a1c2b7d4e6f80a1b2/preview"
},
"assets": ["https://img2htm.com/files/results/3f9a1c2b7d4e6f80a1b2/assets/s01-a01.png"],
"html": "<!DOCTYPE html> ...",
"css": "/* img2htm base styles */ ...",
"content": { "sections": [ ... ], "texts": [ ... ] }
}
API Reference
Reconstruct an image
| Parameter | Type | Description |
|---|---|---|
image_file required* | file | Multipart upload. JPG, PNG or WebP, up to 25 MB. *One of image_file, image_url, image_file_b64 is required. |
image_url | string | Public HTTP(S) URL of the image. |
image_file_b64 | string | Base64-encoded image data. |
mode optional | full | preview | full (default) converts the whole image and charges 1 credit per 15,000 vertical px. preview converts only the top 3,000 px for free. |
lang optional | string | Output document language tag: ko, en, cn, tw, ja, mn, ru, th, id, vi, ar. Text is kept in its source language; this sets <html lang>/dir. |
format optional | json | html | zip | Response format (see above). |
async optional | 1 | Return 202 Accepted immediately; poll GET /api/v1/jobs/{id} for the result. |
Get a job
Returns the job object. Add ?include_html=1 to embed html, css and content.
Get the HTML document
Returns index.html as text/html.
Account
{ "email": "you@example.com", "credits": 38, "pixels_per_credit": 15000, "key": "i2h_ab12cd34…", "calls": 1207 }
Rate limit
60 images per minute per API key. When exceeded the API responds 429 Too Many Requests with a Retry-After: 60 header. Enterprise plans can raise this limit.
Exponential backoff
On 429 or 5xx, retry with exponential backoff: wait 1s, 2s, 4s, 8s … up to 5 attempts, adding random jitter. Never retry 4xx errors other than 429.
delay = min(60, (2 ** attempt) + random(0, 1))
Error codes
| HTTP | Description |
|---|---|
400 | Missing image or unreadable URL. |
401 | Missing, invalid or revoked API key. |
402 | Insufficient credits. Response includes credits_needed and credits_available. |
413 | File exceeds the upload limit. |
415 | Unsupported image type. |
429 | Rate limit exceeded. |
500 | Conversion failed. Credits charged for the job are refunded automatically; error contains the reason. |
Libraries + Tools
Integrations, tools & apps
With Zapier or Make you can connect img2htm to more than 2,000 apps.
Chrome Extension
Right-click any flattened image on any web page and convert it to HTML.
Windows / Mac / Linux
Batch-convert whole folders, drag and drop, offline queue. Uses the same credits as the web app.
API Changelog
Reclaim the web trapped in pixels
Free credits on signup. No credit card required.