Returning data from your JavaScript
Send values from your own JavaScript back with a render using window.customUrlboxData, and read them from the JSON response, the async status response, webhooks or the metadata file.
The js option runs your own JavaScript in the page before Urlbox captures it. That JavaScript can also hand data back to you: assign a value to window.customUrlboxData and Urlbox returns it with the render, under metadata.custom.
It's useful whenever the screenshot alone doesn't tell the whole story: a price or stock level you read from the page, a check your script ran (did the product grid load? was a login wall shown?), or anything else you want to store next to the capture.
js requires the Ultra plan or above.
A minimal example
Set save_metadata to true and assign your data in js:
{ "url": "https://example.com", "save_metadata": true, "js": "window.customUrlboxData = { status: \"rejected\", reason: null, checks: {}, items: [1, null, 3] };"}When the render finishes, your data comes back exactly as you set it, at metadata.custom:
{ "renderUrl": "https://renders.urlbox.com/ub-temp-renders/renders/.../<render-id>.png", "size": 71850, "metadataUrl": "https://renders.urlbox.com/ub-temp-renders/renders/.../<render-id>.json", "metadata": { "title": "Example Domain", "urlRequested": "https://example.com", "urlResolved": "https://example.com/", "custom": { "status": "rejected", "reason": null, "checks": {}, "items": [1, null, 3] } }}Urlbox never interprets the value. A {"status": "rejected"} from your script is just data: the render itself still succeeds, and deciding what "rejected" means is up to you.
Where to read it
The same metadata object, including custom, is returned everywhere a render's result is:
- Synchronous requests return it in the JSON response, as above. For render links, add
response_type=json. - Asynchronous requests return it in the status response once
statusissucceeded, so poll thestatusUrlas usual and readmetadata.custom. See Sync vs Async. - Webhooks carry it in the
render.succeededpayload underresult.metadata. See Webhooks. - The metadata file at
metadataUrlholds the samemetadataobject on its own.
All four contain the same values, including nulls, empty objects and arrays, and keys with dots in them. Read whichever suits your integration, with two things to allow for:
- The inline
metadatais capped at 1 MB. If the whole object (title, tags, links, structured data andcustomtogether) would be larger, its largest fields are left out of the inline copy and listed inmetadata.omittedFields. The file atmetadataUrlalways has everything, so fetch it whenomittedFieldsis present. - Saving the file is best-effort. If it ever fails, the render still succeeds and
metadataUrlis simply absent, so don't rely on the file alone.
How the value is read
Urlbox reads window.customUrlboxData once, after your JavaScript has run and the page has been captured, then converts it with JSON.stringify. That gives a few rules worth knowing:
- Objects, arrays, strings, numbers and
truecome back exactly as you set them. - Unset,
null,false,0and""leave thecustomkey out ofmetadataentirely. If you need to tell "my script ran and found nothing" apart from "my script never ran", always assign an object, for example{ found: false }. - Normal JSON conversion applies: functions and
undefinedvalues are dropped,NaNandInfinitybecomenull,Dateobjects become ISO strings, and aMap,SetorPromisecomes back as{}. - Values that can't be converted, such as a circular reference or a
BigInt, return"custom": {"error": "<message>"}instead. If you use anerrorfield of your own, keep it inside a nested object so you can tell the two apart. - Values assigned later, for example inside a
setTimeoutor after a network request, are missed if they arrive after the capture. Your script runs as an async function and Urlbox waits for it to finish (for up to 30 seconds), soawaitwhat you need before assigning:
const res = await fetch("/api/stock-level");
window.customUrlboxData = { stock: (await res.json()).level };- Values over 1 MB (about a million characters of JSON) aren't returned.
customis{"error": "customUrlboxData is too large: …"}instead, and the render still succeeds. Return a summary rather than, say, the page's whole HTML: there'ssave_htmlfor that.
Using a different variable name
If window.customUrlboxData clashes with something on the page, set custom_data_variable to the name of another global, and assign your data to that instead:
{ "url": "https://example.com", "save_metadata": true, "custom_data_variable": "myScanResult", "js": "window.myScanResult = { headline: document.querySelector(\"h1\")?.textContent ?? null };"}The metadata file
The file at metadataUrl is written by the same render, from the same page load, as the screenshot:
- Its path matches
renderUrl, with.jsonin place of the image extension, and its file name is the render's id. To check a file belongs to the render you polled, confirm it's served over HTTPS fromrenders.urlbox.com(or your own storage bucket or CDN host, if you use one) and that the path ends in<render-id>.json. - The URL has no signature or expiry parameter. It's a public file at a path that can't be guessed.
- Files in Urlbox's default storage are deleted after about 30 days. Copy anything you need to keep, or save renders to your own bucket.
- If the data is sensitive, use
secure_modewith your own private bucket. The metadata file is written only to your bucket, and Urlbox keeps no copy of the render's content, includingcustom, once it has been delivered. - Straight after a render finishes, a fetch of the file can very occasionally fail for a moment. Retry it once before treating it as missing.
Related
- Side Renders covers the rest of
save_metadata(title, open graph and meta tags) and the other artifacts you can save from the same page load. - Webhooks explains the
render.succeededpayload and how to verify theX-Urlbox-Signatureheader.