Your first asset
End-to-end walkthrough — set up a project, hit the proxy, see the mp4 in your page.
Your first asset
This guide ships an animated mp4 to a real page. We'll do it three different ways — pick whichever fits your stack.
Sign up + grab your project key
Create an account. Dashboard creates a default project for you. Open Project → Settings → Proxy and copy the Project key (pk_…).
Set allowed origins
Add the origin where you'll embed the proxy URL (e.g. https://localhost:3000 for dev, https://acme.com for prod). Without this, every request returns 403.
For server-rendered URLs across origins, switch to signed mode instead.
Pick a source image
Any public URL works. For this walkthrough, we'll use https://cdn.acme.com/hero.png. Replace it with one of yours.
The image must be publicly fetchable from Cloudflare — no auth headers, no IP allowlists. Sources behind auth need to be uploaded via POST /api/v1/upload first.
Construct the proxy URL
texthttps://motioness.com/v1/pk_YOUR_KEY/cdn.acme.com/hero.png.mp4
Strip the https:// from the source URL. Keep the rest as-is. End with .mp4 for video, .jpg for poster.
Embed it
The React component is the most polished surface — it ships with hover effects, lazy loading, callbacks, and SSR-safe progressive enhancement. Use plain HTML only when you can't run JS.
bashnpm install @motioness/proxy-client
tsximport { MotionessImg } from '@motioness/proxy-client/react';export function Hero() { return ( <MotionessImg projectKey="pk_YOUR_KEY" src="https://cdn.acme.com/hero.png" motion="medium" durSeconds={4} style={{ width: '100%' }} /> );}
html<script type="module" src="https://motioness.com/proxy-client/element.js"></script><motioness-img project-key="pk_YOUR_KEY" src="https://cdn.acme.com/hero.png" motion="medium" dur-seconds="4" style="width: 100%;"/>
Same effects as the React binding without React.
html<video src="https://motioness.com/v1/pk_YOUR_KEY/cdn.acme.com/hero.png.mp4" poster="https://motioness.com/v1/pk_YOUR_KEY/cdn.acme.com/hero.png.jpg" autoplay muted loop playsinline style="width: 100%; height: auto;"/>
No hover effects, no lazy load. For OG cards, RSS, MDX.
Watch the first request
The <video> element will:
- Show the poster jpg immediately (the source image).
- Hit the mp4 URL — first time, server returns
202 AcceptedandRetry-After: 30. - After ~20-60 seconds, the mp4 finalizes; the next request streams it.
For faster feedback during development, append ?wait_ms=8000:
text…/hero.png.mp4?wait_ms=8000
Server long-polls up to 8 seconds before returning 202.
Inspect the lifecycle (optional)
Open browser devtools → Network → click the mp4 row. Look at response headers:
textX-Motioness-Asset-Id: a25b330a71e2bc6bX-Motioness-Stage: queued | stage1 | stage2 | merge | readyX-Motioness-Eta-Ms: 28000X-Request-Id: req_a1b2c3d4Retry-After: 30
To watch the asset finalize live:
bashcurl -N "https://motioness.com/v1/pk_YOUR_KEY/events/a25b330a71e2bc6b"
Each event arrives as id: <ms> / event: <type> / data: <json>. See SSE streaming.
Refresh
Reload the page. The mp4 streams from the edge cache in ~5ms. The asset is permanent — same URL, same bytes, forever.
What went wrong?
| Symptom | Likely cause | Fix |
|---|---|---|
| 403 on every request | Origin not in allowlist | Add your origin in Project → Settings, or use signed mode |
| 403 with "unknown project key" | Wrong pk_… value | Double-check the dashboard |
| 415 unsupported type | Source isn't png/jpg/webp | Re-encode or upload via /api/v1/upload |
| 413 file too large | Source > 10 MB | Resize before fetching |
| 429 monthly limit reached | Free tier exhausted | Upgrade or wait until reset |
| 502 last generation failed | Vision/i2v failed permanently | Check error_code in asset.failed event; try regenerate with ?prompt=… |