Link a live URL
A space already live on ChatGPT, Vercel, Netlify, GitHub Pages, Cloudflare, Replit or Firebase can be listed where it is. It stays on its host, and Velven plays it in a frame on its Velven page, records a clip for its tile and counts its plays. To have Velven host the files instead, see Hosting.
Check the address
Open Add a space, choose Link a live URL, paste the address and press Check. Velven checks that the page is on a supported host, that it answers, and that it lets Velven frame it.
The page must be public. A deployment behind a login, such as a Vercel preview with Vercel Authentication on, cannot be listed: use its production address. Velven lists the address the page ends on after redirects.
Note: A page that answers with an error, such as a 404, can still be listed, with a warning. Velven checks it again later, and a page that keeps failing is hidden until it answers.
Add the proof tag
Only a verified creator can list a space. The proof is one tag naming your Velven handle, in the page's own HTML. Velven looks for it on the live page when the space is listed or claimed. A space published on Velven needs no tag: the upload is the proof.
Add the tag below inside the <head> of the page at the listed URL.
<meta name="velven" content="@handle">| Host | After adding the tag |
|---|---|
| ChatGPT | In ChatGPT press Share, set “Who has access” to “Anyone on the Internet”, then publish again. |
| Vercel | Deploy the change. |
| Netlify | Deploy the change. |
| GitHub Pages | Push, and wait for Pages to rebuild. |
| Cloudflare | Deploy the change. |
| Replit | Publish again on Replit. |
| Firebase | Deploy again with firebase deploy. |
- Host
- ChatGPT
- After adding the tag
- In ChatGPT press Share, set “Who has access” to “Anyone on the Internet”, then publish again.
- Host
- Vercel
- After adding the tag
- Deploy the change.
- Host
- Netlify
- After adding the tag
- Deploy the change.
- Host
- GitHub Pages
- After adding the tag
- Push, and wait for Pages to rebuild.
- Host
- Cloudflare
- After adding the tag
- Deploy the change.
- Host
- Replit
- After adding the tag
- Publish again on Replit.
- Host
- Firebase
- After adding the tag
- Deploy again with firebase deploy.
Signed in, the add page shows the tag with your handle already in it. Once you copy it or press Check now, the light checks your site every 20 seconds while the tab is in front. Fill in the details while the deploy goes live. When the light finds the tag, it turns green and names your handle. After about 15 minutes without the tag it stops: deploy, then press Check now.
Note: Only the HTML the host sends counts, not a tag a script adds after the page loads. Wait for the deploy and the host's cache: a check that comes too early answers 409 unverified with the change still needed. The older proof, a /.well-known/velven file at the site's origin containing @handle, is still accepted.
Fill in the details and publish
Fill in Title, Type of space and Works on; the rest is optional. Under How it was made, Engine, Model, Tool, Prompt and Repo say how you built it, and people filter by them.
Press Publish once Velven has found your tag. Before that the button reads Save: the page keeps checking your site while it stays open and publishes as soon as it finds the tag.
Note: Your details are kept in this browser for 7 days. You can close the page and come back after the deploy: paste the URL again, press Check, and press Publish once the tag is found.
The clip
Every space gets a 5-second clip for its tile, and the clip's first frame is its thumbnail. After you publish, Velven plays the space in its own browser and records one, which takes a few minutes. Until it lands, only you can see the space, marked Getting ready, and the Clip tab of its edit page shows the progress.
To skip the wait, press Add your own clip on the card before you publish, and the space goes live as soon as it is proven. Later, open the Clip tab on the space's edit page. Under Upload your own video, press Choose a video. Under Record a new clip, say what the clip should show and press Record again. You can ask for 2 new recordings in the space's life.
When the site changes, Velven's background check notices and records again, at most once a day. A clip you uploaded yourself is never replaced. An agent can ask for a new clip through the API.
Supported hosts
Velven reads the host from the address and the response headers, after redirects, and refuses any other host with a 422.
| Host | Recognised by |
|---|---|
| ChatGPT | A chatgpt.site address. Publish the site with “Who has access” set to “Anyone on the Internet”: a site only its owner can open answers 401, and Velven cannot check it. |
| Vercel | A vercel.app address, or a custom domain whose response headers say Vercel. |
| Netlify | A netlify.app address, or a custom domain whose response headers say Netlify. |
| GitHub Pages | A github.io address, or a custom domain served by GitHub Pages. A repository page on github.com is not a Pages site and is refused. |
| Cloudflare | A workers.dev or pages.dev address. A custom domain on Cloudflare is not recognised yet, since the server: cloudflare header proves nothing. |
| Replit | A replit.app address. A custom domain is not recognised, since Replit adds no header of its own. A replit.dev address is the workspace's development preview, not a deployment. |
| Firebase | A web.app or firebaseapp.com address. A custom domain is not recognised, since Firebase adds no header of its own. |
- Host
- ChatGPT
- Recognised by
- A chatgpt.site address. Publish the site with “Who has access” set to “Anyone on the Internet”: a site only its owner can open answers 401, and Velven cannot check it.
- Host
- Vercel
- Recognised by
- A vercel.app address, or a custom domain whose response headers say Vercel.
- Host
- Netlify
- Recognised by
- A netlify.app address, or a custom domain whose response headers say Netlify.
- Host
- GitHub Pages
- Recognised by
- A github.io address, or a custom domain served by GitHub Pages. A repository page on github.com is not a Pages site and is refused.
- Host
- Cloudflare
- Recognised by
- A workers.dev or pages.dev address. A custom domain on Cloudflare is not recognised yet, since the
server: cloudflareheader proves nothing.
- Host
- Replit
- Recognised by
- A replit.app address. A custom domain is not recognised, since Replit adds no header of its own. A replit.dev address is the workspace's development preview, not a deployment.
- Host
- Firebase
- Recognised by
- A web.app or firebaseapp.com address. A custom domain is not recognised, since Firebase adds no header of its own.
Note: Size your space to the viewport, not to a fixed ratio. On a desktop it fills the page's width at the window's height; on a phone it takes the whole screen.
Allow Velven to frame your page
Every space plays inside its Velven page; there is no option to open it in a new tab. So its host must let velven.ai frame it. All 7 hosts allow that by default, and most pages need nothing. A page that sends its own headers must allow velven.ai in them:
- A
Content-Security-Policywithframe-ancestorsmust namehttps://velven.ai(or allow every site with*orhttps:).'self'alone refuses Velven. - Without
frame-ancestors,X-Frame-Optionsmust not beDENYorSAMEORIGIN. When both are sent,frame-ancestorswins.
This header keeps the page framable by its own site and by Velven:
Content-Security-Policy: frame-ancestors 'self' https://velven.aiVelven reads the headers when the space is listed, and again on its background check. The agent API refuses a page that blocks framing with 422 unframeable and the change for its host. A listed space whose host starts refusing frames leaves Velven until the header is back. Its creator sees the fix on the space's page and its edit page, and can press Check again on either.
Note: The frame is sandboxed: a space cannot open alert or confirm dialogs, start downloads or navigate the Velven page away.
ChatGPT
A ChatGPT site sends no headers of its own and always allows framing. Nothing to do.
Vercel
Add this to vercel.json at the project root, merged into any headers list already there. A Next.js app can set the same header in next.config instead.
{ "headers": [ { "source": "/(.*)", "headers": [ { "key": "Content-Security-Policy", "value": "frame-ancestors 'self' https://velven.ai" } ] } ]}Remove any X-Frame-Options header the app sets (a security preset, a middleware).
Deploy the change.
Netlify
Add this to a _headers file in the publish directory, or the same rule under [[headers]] in netlify.toml.
/* Content-Security-Policy: frame-ancestors 'self' https://velven.aiRemove any X-Frame-Options header the app sets (a security preset, a middleware).
Deploy the change.
GitHub Pages
GitHub Pages sets no headers and always allows framing. If a page there refuses framing, something in front of it is blocking it.
Cloudflare
On Pages, or a Worker that serves static assets, add this to a _headers file in the output (assets) directory. On a Worker whose fetch handler builds the page, set the header on the response there.
/* Content-Security-Policy: frame-ancestors 'self' https://velven.aiRemove any X-Frame-Options header the app sets (a security preset, a middleware).
Deploy the change.
Replit
On a static deployment, add this to the .replit file at the project root. On an Autoscale or Reserved VM deployment, set the header on the response in the server.
[[deployment.responseHeaders]]path = "/*"name = "Content-Security-Policy"value = "frame-ancestors 'self' https://velven.ai"Remove any X-Frame-Options header the app sets (a security preset, a middleware).
Publish again.
Firebase
Add this to firebase.json at the project root, merged into the hosting block and any headers list already there.
{ "hosting": { "headers": [ { "source": "**", "headers": [ { "key": "Content-Security-Policy", "value": "frame-ancestors 'self' https://velven.ai" } ] } ] }}Remove any X-Frame-Options header the app sets (a security preset, a middleware).
Deploy again with firebase deploy.
What Velven checks, and when
Velven checks a linked page when it is listed, claimed or moved, in the background, and when you press a button for it. The background check runs every 6 hours and visits the spaces checked longest ago first, so a space's turn can come less often. The proof tag is read only at a listing, a claim and a move; removing it later changes nothing.
| When | What |
|---|---|
Listing, on the add page or POST /api/spaces | The host, that the page answers and does not ask visitors to sign in, the framing headers and the proof. It may also be checked against the malware and phishing list. The page's boards block is read after the space is listed; a bad block never stops the listing. |
A claim, at /s/{slug}/claim or POST /api/spaces/verify | The proof. |
A move, on the edit page's Settings tab or POST /api/spaces/{slug}/move | The new page, as a listing checks it: the host, that it answers with a page and does not ask visitors to sign in, and the framing headers. On a claimed space, also the proof and the boards block. It may also be checked against the malware and phishing list. |
| In the background | That the page still answers and allows framing, its boards block on a claimed space, and whether it changed. It may also be checked against the malware and phishing list. A page that changed gets the same safety check as a hosted version, at most once a day, and one judged unsafe is hidden until Velven reviews it. A page that fails to answer twice is marked dead until it answers again. |
| Check again, on the space's page and its edit page while its host refuses frames | The same as the background check, at once. A page that allows framing again goes back on Velven. |
| Check my page now, on the edit page's Leaderboards tab | The boards block, at once. |
- When
- Listing, on the add page or
POST /api/spaces - What
- The host, that the page answers and does not ask visitors to sign in, the framing headers and the proof. It may also be checked against the malware and phishing list. The page's boards block is read after the space is listed; a bad block never stops the listing.
- When
- A claim, at
/s/{slug}/claimorPOST /api/spaces/verify - What
- The proof.
- When
- A move, on the edit page's Settings tab or
POST /api/spaces/{slug}/move - What
- The new page, as a listing checks it: the host, that it answers with a page and does not ask visitors to sign in, and the framing headers. On a claimed space, also the proof and the boards block. It may also be checked against the malware and phishing list.
- When
- In the background
- What
- That the page still answers and allows framing, its boards block on a claimed space, and whether it changed. It may also be checked against the malware and phishing list. A page that changed gets the same safety check as a hosted version, at most once a day, and one judged unsafe is hidden until Velven reviews it. A page that fails to answer twice is marked dead until it answers again.
- When
- Check again, on the space's page and its edit page while its host refuses frames
- What
- The same as the background check, at once. A page that allows framing again goes back on Velven.
- When
- Check my page now, on the edit page's Leaderboards tab
- What
- The boards block, at once.
Publish with an agent has the API calls, and Leaderboards the boards block.
Claim a space Velven listed
Velven lists some spaces itself, marked Unclaimed and credited to their creator. If one is yours, add the proof tag to it and deploy. Press Claim on its page, sign in, and press Check now. Its plays stay, and it moves to your handle. An agent claims it with POST /api/spaces/verify.
Move to another host
A space that moves to a new URL keeps its listing: its slug, plays, likes, boards, scores, saves and page text stay. Put the proof tag on the new page and allow framing there, deploy, then enter the new URL under Move to a new address on the Settings tab of the space's edit page.
Velven reads the boards block on the new page. Boards the old page declared and the new one does not are withdrawn, with their scores kept, so copy the block across.
An agent moves it with POST /api/spaces/{slug}/move. Move to another host has the call and what to update on the new host, and the REST API every refusal. To move the space onto Velven's own hosting, see Move a linked space onto Velven.
Note: A server that posts scores or checks identity tokens needs the move too: a board secret in the new host's environment, and the new origin as the tokens' audience.