Everything you need to get your game on Playlink — from technical requirements to optimization tips.
👋 This guide helps your clip succeed
Most clips that perform poorly have simple issues that are easy to fix. Here are the top 5 things to get right:
📱 Design for portrait — players hold their phone upright
👆 Add touch controls — most players are on mobile
🔧 Set iframe headers — so your clip loads inside Playlink
🎯 Keep buttons in the center — edges are hard to reach
⚡ Stay under 7MB — fast loading = more plays
Takes about 5 minutes to read. Each section has examples and code snippets.
A Playable Clip is NOT your full game.
It's a small, self-contained web build of the best 10–60 seconds of your game. Think of it as a movie trailer — you pick the most exciting moment, cut it down, and make it stand on its own.
Players see your clip, play it instantly in their browser with zero downloads, and if they like it — they tap the action button to open your store page or play the full game. Your clip runs inside a secure sandbox on Playlink. You host it on your own server (Vercel, Netlify, etc.) — we just load the URL.
Duration
10–60 seconds
You choose. Default 30.
Format
Web page (HTML/JS/CSS)
Loaded in an iframe
Hosting
Your server
Vercel, Netlify, own server
Cost
Free
Upload and reach players for $0
Already have a playable ad, or a Unity/Godot/Construct web export?
You already have your clip — skip everything below and go straight to hosting.
Drag your file to app.netlify.com/drop for an instant HTTPS link. Vercel and GitHub Pages work too. Your URL must be https:// and must not block iframe embedding — our upload check will flag it if there's a problem.
Rosebud AI
Games — text → browser game
Free tier (limited) / ~$19.99 for commercial rights
PlayableMaker
HTML5-focused
Single file, under 5MB
In Claude.ai: Settings → Connectors → Add custom connector.
Higgsfield
mcp.higgsfield.ai/mcp
Images, backgrounds, mockups — games AND apps — Free / OAuth
Ludo.ai
mcp.ludo.ai/mcp
Sprites, animation, SFX — games only — ⚠️ Requires $50/mo Pro plan
🎮 Games
Describe a clip: "hold to fly, release to fall, collect coins, dodge obstacles"
📱 Apps
Describe the moment: "enter a number, tap calculate, see an animated result" — the "aha" moment your user should feel in 30 seconds.
A "game loop" is code that runs many times per second — checking input, moving things, redrawing the screen. You don't need to understand it to build one — Claude writes it — but when something "feels off" (slow, jerky), that's almost always where the problem is.
⚠️ Don't ask the tool to generate the whole clip
Both tools can generate video, which creates something to watch, not play. The interactive logic (touch/input/calculation) must be real code. These tools are for assets only.
Describe the core — the mechanic for a game, the moment for an app — and let Claude write the code.
⚠️ Test it standalone first
Open the file directly in its own browser tab, not just in the preview. Some problems only show up when you compare a standalone run to running inside an iframe.
Add assets (Ludo.ai or Higgsfield, depending on what you're building) — embed them, then re-check the file size (the 7MB limit).
⚠️ Test on a real phone, not just desktop
A lot of problems (sizing, speed, orientation) only show up there.
A precise description = a fast fix. "The obstacles are small and slow in landscape" helps far more than "it's broken." Tell Claude exactly what you're seeing.
⚠️ Common trap
If sizes/speed are derived from screen height but hit-distances are fixed absolute numbers, switching orientation (portrait↔landscape) breaks the balance. If it "feels different" between modes, this is probably why.
Repeat steps 2–6 until it actually works — not "it compiled," but tested and working.
Faster is better — every second compounds
Keep it under 7MB. Every extra second of loading time means fewer players reach the fun part before they tap away — and every dropped player is a missing store tap. A fast, focused clip converts better.
You don't need a hard cutoff to aim at. Focus on the one thing that matters: show something on screen — a character, a button, a moving element — as fast as possible, even on a 4G phone. The faster, the more reach you get.
Playlink loads your clip inside a sandboxed iframe with sandbox="allow-scripts". This is the most restrictive mode that still allows JavaScript to run. Your clip gets a unique opaque origin — it cannot access the parent page, other frames, or any storage tied to your real domain.
✓ Works
• JavaScript execution
• Canvas 2D and WebGL
• Web Audio API (after user tap)
• Touch, pointer, keyboard events
• CSS animations and transitions
• requestAnimationFrame
• setTimeout / setInterval
• fetch() to your own server (with CORS)
• WebAssembly (Wasm)
✗ Blocked
• localStorage / sessionStorage
• IndexedDB
• Cookies (document.cookie)
• Opening new tabs (window.open)
• Redirecting parent page
• Camera / microphone access
• Geolocation
• File downloads
• Clipboard access
• Form submissions
Important: No local storage
Because the sandbox assigns your clip a unique opaque origin, localStorage, sessionStorage, IndexedDB, and cookies are all blocked. If your game uses any of these to save progress, scores, or settings — it will throw errors. Since clips are 10–60 seconds, persistent storage is rarely needed. If you must store temporary state, use JavaScript variables in memory.
Because your clip runs on an opaque origin, any fetch() or XMLHttpRequest from your clip to your server is a cross-origin request. Your server must respond with the CORS header:
Access-Control-Allow-Origin: *
When do you NOT need CORS?
If your clip is a single HTML file with all assets inlined (base64 images, inline CSS, inline JS) — it makes no network requests, so CORS is irrelevant. CORS is only needed when your game loads external files (images, audio, JSON, fonts) from your server at runtime.
Some servers and hosting platforms block iframe embedding by default. If your server sends any of these headers, your game will not load on Playlink:
X-Frame-Options: DENY X-Frame-Options: SAMEORIGIN Content-Security-Policy: frame-ancestors 'self' Content-Security-Policy: frame-ancestors 'none'
To explicitly allow embedding, either remove these headers entirely, or set:
Content-Security-Policy: frame-ancestors *
Playlink automatically checks for these headers when you submit your clip. If embedding is blocked, you'll see an error before upload.
Vercel
Add vercel.json config
Netlify
Add _headers file
Cloudflare Pages
Add _headers file
Firebase Hosting
Add firebase.json headers
Your own server
Configure CORS + CSP
AWS S3 + CloudFront
Configure CORS in bucket
itch.io (embed URL)
Only the html-classic.itch.zone embed URL works, not the game page URL
GitHub Pages
Blocks iframe embedding — cannot be changed
{
"headers": [
{
"source": "/(.*)",
"headers": [
{ "key": "Access-Control-Allow-Origin", "value": "*" },
{ "key": "Access-Control-Allow-Methods", "value": "GET, OPTIONS" }
]
}
]
}/* Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, OPTIONS
location / {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, OPTIONS";
}Header set Access-Control-Allow-Origin "*"
The majority of players are on mobile. Your clip must work with touch controls.
Most Playlink pages are portrait, like a TikTok clip. If your game is landscape, that's fully supported too — visitors on mobile will see a 'rotate your phone' prompt automatically.
Example: Your racing game is landscape. For the Playable Clip, create a top-down view where the car drives upward (portrait-friendly). The full game stays landscape — the clip is just a 30-second taste.
Playlink shows a store button fixed at the bottom of the screen. Keep your own buttons and controls above the bottom ~80px so nothing overlaps.
Browsers block autoplay audio
All modern browsers (Chrome, Safari, Firefox) block audio that plays without user interaction. Inside a sandboxed iframe, this is even stricter. Your game must only start audio after the player taps or clicks — not on page load. If you call audioContext.resume() or audio.play() on load, it will silently fail.
Best practice: Add a "Tap to start" screen. When the player taps, initialize audio in that same event handler. This guarantees the browser allows sound.
⚠️ Howler.js / XHR audio will fail
Libraries like Howler.js load audio files via XMLHttpRequest by default. Inside our sandbox, the origin is null, so XHR to external URLs will be blocked by CORS — even your own server.
Fix options:
1. Use Howler with html5 mode: new Howl({ src: ['sound.mp3'], html5: true }) — uses HTML5 Audio instead of XHR
2. Use native Audio API: new Audio('sound.mp3') — no CORS needed
3. Inline audio as base64: embed audio directly in HTML — no network requests at all
Keep your clip under 7MB. The longer it takes to become playable, the more visitors drop off before they even see the fun part — and every dropped visitor is a missed store tap. A fast first frame is the single biggest lever you control.
< 1s to interactive
Excellent. Most players make it past the loading bar.
1-3s to interactive
Good. Most clips fit here.
3-5s to interactive
OK, but engagement starts to dip — fewer plays reach completion.
5s+ to interactive
Workable, but you'll see noticeably less reach over time.
• Cut your build — Don't ship the full game. Export only the level/scene you want to show.
• Lazy-load assets — Show a sprite or placeholder first, swap in real assets after first interaction.
• Compress textures — Use WebP instead of PNG. Reduce resolution for mobile.
• Compress audio — Use OGG/MP3 at 64-128kbps. Remove background music if it's heavy.
• Minify JS — Most build tools do this automatically (Vite, Webpack).
• Lazy load — Load assets as needed, not all upfront.
• Remove unused code — Tree-shaking, dead code elimination.
There's no hidden algorithm and no ranking system. Every clip gets its own page, and you see exactly how it performs in your dashboard at /creator/stats/[id]. Three numbers tell you everything:
Retention
Where in your clip do visitors leave? The retention curve shows exactly which second loses people. If everyone drops at second 3, your opening is too slow. If they make it to second 20 but leave before the end, the pacing needs work.
Sources
Which channel or creator is sending the most plays? See if your traffic comes from a shared link, a specific social post, or direct visits. Double down on what works.
Tap rate
What percentage of plays end with a tap to your store page? This is the number that matters most — it tells you whether your clip is actually converting visitors into potential customers.
The bottom line
Make a clip that visitors play to the end. That's the single biggest lever on your tap-to-store rate. Check your Stats page to see exactly where people drop off — then fix that moment.
Already have a web game? — You might be ready. Just paste the URL and test with section 12.
Unity — Export as WebGL build. Uncheck "compression" for faster loading (or use Brotli if your server supports it). Host the build folder on Vercel/Netlify. Set the scene to the exact moment you want to show.
Godot — Export as HTML5. Godot produces a lightweight build. Upload to Vercel or Netlify.
Unreal Engine — HTML5 export (UE4) or a Pixel Streaming demo page. UE5 doesn't officially support HTML5, but community plugins exist.
Phaser / PixiJS / Three.js — Native web. Bundle with Vite and deploy.
Native / Console games — Build a small HTML5 demo that captures the feel of your game. Even a simple interactive scene or mini-game works. It doesn't have to be the actual game — just something that represents it.
Free hosting: Vercel, Netlify, and Cloudflare Pages all work and are free.
This is the most important step
If you test your game in a sandboxed iframe before uploading, you'll catch every issue yourself. This is the exact same environment Playlink uses.
Save this as test.html and open it locally:
<!DOCTYPE html>
<html>
<body style="margin:0; background:#000;">
<iframe
src="https://YOUR-GAME-URL-HERE"
width="390"
height="844"
sandbox="allow-scripts"
style="border:none;"
></iframe>
</body>
</html>Open DevTools (F12) → Console. Check that:
Failed to read 'localStorage' from 'Window'
Cause: Your game uses localStorage which is blocked in the sandbox.
Fix: Replace localStorage with in-memory JavaScript variables. For a 30-second clip, you don't need persistent storage.
Blocked by CORS policy: No 'Access-Control-Allow-Origin' header
Cause: Your server doesn't send CORS headers.
Fix: Add Access-Control-Allow-Origin: * to your server config (see section 4 and 6).
Refused to display in a frame because it set 'X-Frame-Options'
Cause: Your server blocks iframe embedding.
Fix: Remove X-Frame-Options header or set Content-Security-Policy: frame-ancestors * (see section 5).
The AudioContext was not allowed to start
Cause: Audio started without user interaction.
Fix: Only call audio.play() or audioContext.resume() inside a click/tap event handler (see section 8).
Access to XMLHttpRequest at '...mp3' from origin 'null' has been blocked by CORS
Cause: Audio library (like Howler.js) loads sound files via XMLHttpRequest. In our sandbox, origin is null so XHR is blocked.
Fix: If using Howler.js, add html5: true — new Howl({ src: ['sound.mp3'], html5: true }). Or use native new Audio('sound.mp3') instead. Or inline audio as base64 (see section 8).
Blank white screen, no errors in console
Cause: Game might be redirecting, or it requires allow-same-origin.
Fix: Check if your game redirects on load. If it needs cookies/localStorage, refactor to use in-memory state.
Game works locally but not on Playlink
Cause: Most likely CORS or CSP headers missing.
Fix: Test with the iframe test page in section 12. The console will show the exact error.
These are the most common reasons clips get skipped or perform poorly. Follow these guidelines to maximize engagement.
🎮 Multiplayer games
Players are alone in your clip — there's no matchmaking or chat. If your game is multiplayer, make sure the clip has a single-player mode or AI opponent. A player who sees "waiting for opponent..." for 30 seconds will skip immediately.
🔇 Start with sound off
People open your link on the bus, at night, in class. Loud sound on load = instant close. Start muted and let the player turn on sound themselves. Most browsers block autoplay audio anyway, but some don't — be safe.
👆 Touch controls are mandatory
Most Playlink users are on mobile. If your game needs a keyboard (arrows, WASD, spacebar), add touch controls — on-screen buttons, virtual joystick, or swipe gestures. A keyboard-only clip is desktop-only, missing most of the audience.
⚡ Keep it light and fast
Your clip is 30 seconds. If it takes 10 seconds to load, a third of the experience is wasted on a loading bar. There's no upload size limit, but lighter clips become playable faster. Compress textures, lazy-load audio, minify your JS, and trim anything you don't need for the clip.
🚫 No ads in your clip
Remove all ads (AdMob, Unity Ads, etc.) from your clip version. The clip is your trailer — not a revenue source. A 5-second ad in a 30-second clip is a terrible first impression. Revenue comes from the full version.
📱 Portrait-first design
Most Playlink pages are vertical (portrait). If your game is landscape, that's supported - just make sure it looks right in a 16:9 frame, since we show a rotate prompt on mobile. Most responsive games adapt automatically. If yours doesn't, add width: 100%; height: 100% to your container CSS.