Connect Visualizer attribution to paid orders#
Capture the attribution snapshot published by the Visualizer SDK, keep it with the customer's cart or checkout, and report the final paid order from your server.
The SDK does not modify your cart or report orders automatically. Your integration must:
- capture the latest snapshot in the storefront;
- keep the complete snapshot with the cart and order; and
- send the paid order to Ideal House from a trusted server.
1. Capture the snapshot#
Read the ih_visualizer cookie when your storefront initializes and listen for ih:visualizer to receive updates. The cookie contains URL-encoded JSON. The browser event provides the same object in event.detail.
function readVisualizerAttribution() {
const prefix = 'ih_visualizer='
const value = document.cookie
.split(';')
.map(part => part.trim())
.find(part => part.startsWith(prefix))
?.slice(prefix.length)
if (!value) return null
try {
return JSON.parse(decodeURIComponent(value))
} catch {
return null
}
}
window.addEventListener('ih:visualizer', event => {
saveAttributionWithCart(event.detail)
})
const currentAttribution = readVisualizerAttribution()
if (currentAttribution) {
saveAttributionWithCart(currentAttribution)
}
Implement saveAttributionWithCart with your commerce platform's cart attributes, checkout metadata or server-side session API.
The snapshot fields are:
{
"visitor_id": "anonymous-visitor-id",
"session_id": "visualizer-session-id",
"categories": ["wall", "furniture"],
"last_used_at": "2026-09-10T12:34:56.000Z"
}
Store and replace the complete snapshot together. Do not rename, partially copy or modify its values. Treat data read from a cookie as untrusted and discard it if it is not a complete object with this shape.
If your checkout uses another hostname or an external platform, copy the snapshot into the cart or server-side session before the customer leaves the storefront page.
2. Keep it with the order#
When payment completes, reconstruct the original snapshot from your cart, checkout or order metadata. If no complete snapshot is available, use null rather than constructing a partial object.
Store the snapshot as a JSON value or use these recommended metadata fields:
| Metadata field | Value |
|---|---|
idealhouse_visitor_id | visitor_id |
idealhouse_session_id | session_id |
idealhouse_categories | categories joined with commas |
idealhouse_last_used_at | last_used_at |
Convert idealhouse_categories back to a JSON string array before reporting the order.
3. Report the paid order#
Call this endpoint from your backend or paid-order webhook handler. Never call it from browser JavaScript.
POST <IDEALHOUSE_API_URL>/integrations/commerce/order-events
Content-Type: application/json
X-Client-Id: <CLIENT_ID>
X-Client-Secret: <CLIENT_SECRET>
Use credentials for the same Ideal House shop as the storefront SDK. Do not include shop_id or shopId in the request body.
curl -X POST "<IDEALHOUSE_API_URL>/integrations/commerce/order-events" \
-H "Content-Type: application/json" \
-H "X-Client-Id: <CLIENT_ID>" \
-H "X-Client-Secret: <CLIENT_SECRET>" \
-d '{
"schema_version": 1,
"event_id": "store-42-order-paid-1001",
"event_type": "order.paid",
"source": {
"platform": "custom",
"store_id": "store-42"
},
"order": {
"id": "order-1001",
"order_number": "#1001",
"customer_po_number": null,
"created_at": "2026-09-10T11:55:00.000Z",
"paid_at": "2026-09-10T12:00:00.000Z",
"financial_status": "paid",
"currency": "USD",
"subtotal": "125.50",
"total": "143.25",
"line_items": [
{
"id": "line-1",
"product_id": "product-1",
"variant_id": "variant-1",
"sku": "WP-100",
"product_type": "Wallpaper",
"quantity": 2,
"unit_price": "62.75",
"total_price": "125.50"
}
]
},
"visualizer": {
"visitor_id": "anonymous-visitor-id",
"session_id": "visualizer-session-id",
"categories": ["wall", "furniture"],
"last_used_at": "2026-09-09T12:00:00.000Z"
}
}'
Send monetary values as JSON strings. Include a timezone in every timestamp. Send only the documented fields; customer names, email addresses, phone numbers and billing or shipping addresses are not accepted.
For an order without a complete attribution snapshot, the visualizer field is still required:
{
"visualizer": null
}
4. Handle retries#
Create a stable event_id for the paid-order event and reuse it for every retry.
| Response | What to do |
|---|---|
| HTTP 200 | Success. duplicate: true is also a successful result. |
Network error or HTTP 5xx | Retry with backoff and the same event_id. |
| HTTP 400 | Correct the request before retrying. |
| HTTP 401 or 403 | Check your server credentials. |
| HTTP 409 | Stop and check whether the event_id was used for another order. |
Example success response:
{
"accepted": true,
"duplicate": false,
"visualizer_assisted": true
}
5. Integration checklist#
- Confirm that the storefront can read
ih_visualizerafter using the Visualizer. - Confirm that the
ih:visualizerlistener updates cart or checkout metadata. - Confirm that the complete snapshot reaches the paid order.
- Submit a paid test order from your server and expect HTTP 200.
- Submit the same event again with the same
event_idand acceptduplicate: trueas success. - Submit an order without attribution using
"visualizer": null. - Confirm that Client Secret and customer personal data never appear in browser requests or submitted order data.