How to Screenshot a Twitter Embed via API
Render a Twitter (X) embed as a PNG using the HTML to Image HTML endpoint. Useful for newsletters, blog inserts and archives where the live embed cannot run.
Want it faster? Use the Tweet Mockup Card template and skip the embed widget entirely. Send the username, handle, body and timestamp as JSON.
HTML and CSS
<blockquote class="twitter-tweet">
<a href="https://twitter.com/username/status/1298730289737293824"></a>
</blockquote>
<script async src="https://platform.twitter.com/widgets.js"></script>
body { margin: 0; padding: 16px; background: white; }
.twitter-tweet { margin: 0 !important; }
ms_delay
Add a 1 second delay so the embed widget has time to render before capture. The Twitter widget script does not expose a stable selector, so ms_delay is the right tool here. See also wait_for_selector for cases where you control the markup.
Code examples
cURL
curl -X POST https://app.html2img.com/api/html \
-H "X-API-Key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"html": "<blockquote class=\"twitter-tweet\"><a href=\"https://twitter.com/username/status/1298730289737293824\"></a></blockquote><script async src=\"https://platform.twitter.com/widgets.js\"></script>",
"css": "body { margin: 0; padding: 16px; background: white; } .twitter-tweet { margin: 0 !important; }",
"width": 550,
"height": 321,
"ms_delay": 1000
}'
PHP
$response = file_get_contents('https://app.html2img.com/api/html', false, stream_context_create([
'http' => [
'method' => 'POST',
'header' => "X-API-Key: " . getenv('HTML2IMG_API_KEY') . "\r\nContent-Type: application/json\r\n",
'content' => json_encode([
'html' => '<blockquote class="twitter-tweet"><a href="https://twitter.com/username/status/1298730289737293824"></a></blockquote><script async src="https://platform.twitter.com/widgets.js"></script>',
'css' => 'body { margin: 0; padding: 16px; background: white; } .twitter-tweet { margin: 0 !important; }',
'width' => 550,
'height' => 321,
'ms_delay' => 1000,
]),
],
]));
$url = json_decode($response, true)['url'];
Node.js
const response = await fetch('https://app.html2img.com/api/html', {
method: 'POST',
headers: {
'X-API-Key': process.env.HTML2IMG_API_KEY,
'Content-Type': 'application/json',
},
body: JSON.stringify({
html: '<blockquote class="twitter-tweet"><a href="https://twitter.com/username/status/1298730289737293824"></a></blockquote><script async src="https://platform.twitter.com/widgets.js"></script>',
css: 'body { margin: 0; padding: 16px; background: white; } .twitter-tweet { margin: 0 !important; }',
width: 550,
height: 321,
ms_delay: 1000,
}),
});
const { url } = await response.json();
Python
import os
import requests
response = requests.post(
'https://app.html2img.com/api/html',
headers={'X-API-Key': os.environ['HTML2IMG_API_KEY']},
json={
'html': '<blockquote class="twitter-tweet"><a href="https://twitter.com/username/status/1298730289737293824"></a></blockquote><script async src="https://platform.twitter.com/widgets.js"></script>',
'css': 'body { margin: 0; padding: 16px; background: white; } .twitter-tweet { margin: 0 !important; }',
'width': 550,
'height': 321,
'ms_delay': 1000,
},
)
url = response.json()['url']
How it works
- We use Twitter’s official embed code to render the tweet.
- The CSS sets a white background and clears the default margin.
- The API request includes both HTML and CSS plus an
ms_delayof 1 second. - A fixed
widthof 550 matches Twitter’s preferred embed width.
Common pitfalls
- Embed widget never loads. Twitter’s widget script can be blocked by ad blockers or rate limited. Use the Tweet Mockup Card template for stable, reproducible output.
- Tweet is from a private or deleted account. The widget renders an empty box. Verify the URL is publicly accessible before rendering.
ms_delayis too short. A flaky network can push the widget past 1 second. Bump to 2000ms if your renders fail intermittently.