Previews
Render an ad, or a draft creative, exactly as Meta renders it
Previews
Meta renders previews server-side and hands back an embeddable <iframe> HTML snippet, one per requested format. Drop it into your UI and the user sees the real ad, in the real placement, without opening Ads Manager.
Two entry points: one for an ad that already exists, one for a creative you haven't created yet.
Preview an existing ad
GET /v1/ads/{adId}/preview accepts either the Zernio ad id or the Meta ad id.
const { data } = await zernio.adcreatives.getAdPreviews({
path: { adId: 'AD_ID' },
query: { formats: 'DESKTOP_FEED_STANDARD,INSTAGRAM_STORY' },
});
data.previews.forEach(p => console.log(p.format, p.body));data = client.ad_creatives.get_ad_previews(
ad_id="AD_ID",
formats="DESKTOP_FEED_STANDARD,INSTAGRAM_STORY",
)
for p in data.previews:
print(p.format)curl "https://zernio.com/api/v1/ads/AD_ID/preview?formats=DESKTOP_FEED_STANDARD,INSTAGRAM_STORY" \
-H "Authorization: Bearer YOUR_API_KEY"Up to 10 formats per call. Omitting formats returns DESKTOP_FEED_STANDARD.
Preview before you create
POST /v1/ads/preview renders a creative that doesn't exist on an ad yet. Pass exactly one of existingCreativeId or creativeSpec.
// A: a creative id from a previous create (ad.creative.creativeId, or the library)
const { data } = await zernio.adcreatives.generateAdPreviews({
body: {
accountId: 'ACCOUNT_ID',
adAccountId: 'act_1234567890',
existingCreativeId: '120250000000000000',
formats: ['DESKTOP_FEED_STANDARD', 'INSTAGRAM_STORY'],
},
});
// B: a raw Meta creative spec, forwarded verbatim
const { data: draft } = await zernio.adcreatives.generateAdPreviews({
body: {
accountId: 'ACCOUNT_ID',
adAccountId: 'act_1234567890',
formats: ['DESKTOP_FEED_STANDARD'],
creativeSpec: {
object_story_spec: {
page_id: 'PAGE_ID',
link_data: {
link: 'https://example.com',
message: 'Primary text',
name: 'Headline',
picture: 'https://cdn.example.com/i.jpg',
call_to_action: { type: 'LEARN_MORE', value: { link: 'https://example.com' } },
},
},
},
},
});data = client.ad_creatives.generate_ad_previews(
account_id="ACCOUNT_ID",
ad_account_id="act_1234567890",
existing_creative_id="120250000000000000",
formats=["DESKTOP_FEED_STANDARD", "INSTAGRAM_STORY"],
)
draft = client.ad_creatives.generate_ad_previews(
account_id="ACCOUNT_ID",
ad_account_id="act_1234567890",
formats=["DESKTOP_FEED_STANDARD"],
creative_spec={
"object_story_spec": {
"page_id": "PAGE_ID",
"link_data": {
"link": "https://example.com",
"message": "Primary text",
"name": "Headline",
"picture": "https://cdn.example.com/i.jpg",
"call_to_action": {"type": "LEARN_MORE", "value": {"link": "https://example.com"}},
},
}
},
)curl -X POST "https://zernio.com/api/v1/ads/preview" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "ACCOUNT_ID",
"adAccountId": "act_1234567890",
"formats": ["DESKTOP_FEED_STANDARD", "INSTAGRAM_STORY"],
"creativeSpec": {
"object_story_spec": {
"page_id": "PAGE_ID",
"link_data": {
"link": "https://example.com",
"message": "Primary text",
"name": "Headline",
"picture": "https://cdn.example.com/i.jpg",
"call_to_action": { "type": "LEARN_MORE", "value": { "link": "https://example.com" } }
}
}
}
}'No upload needed for a spec preview. link_data.picture takes a plain public image URL, so you can preview a design before it ever reaches the ad account's image library. That makes creativeSpec the cheap way to build a live preview into a creative editor.
Formats
formats passes through to Meta's ad_format enum, which has roughly 60 values. We deliberately don't mirror the list here: it changes, and an unknown value returns Meta's own 400 enumerating every valid format, which is always current.
The ones you'll reach for most:
| Format | Placement |
|---|---|
DESKTOP_FEED_STANDARD | Facebook desktop feed |
MOBILE_FEED_STANDARD | Facebook mobile feed |
INSTAGRAM_STANDARD | Instagram feed |
INSTAGRAM_STORY | Instagram Stories |
INSTAGRAM_REELS | Instagram Reels |
FACEBOOK_STORY_MOBILE | Facebook Stories |
MOBILE_BANNER | Audience Network banner |
Rendering the snippet
Each entry in previews[] carries the format and Meta's HTML. The HTML is an <iframe> pointing at a signed Meta URL, so:
- Render it as-is. Rewriting the markup or proxying the frame breaks the signature.
- The URL is short-lived. Fetch previews when the user opens the panel, don't cache them for later.
- The frame has fixed dimensions per format. Scale with CSS
transformrather than changing the iframe's width and height attributes.