velven
Docs
Menu

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.

View as Markdown

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.

HTML
<meta name="velven" content="@handle">
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
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: cloudflare header 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-Policy with frame-ancestors must name https://velven.ai (or allow every site with * or https:). 'self' alone refuses Velven.
  • Without frame-ancestors, X-Frame-Options must not be DENY or SAMEORIGIN. When both are sent, frame-ancestors wins.

This header keeps the page framable by its own site and by Velven:

HTTP
Content-Security-Policy: frame-ancestors 'self' https://velven.ai

Velven 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.

JSON
{  "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.

Text
/*  Content-Security-Policy: frame-ancestors 'self' https://velven.ai

Remove 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.

Text
/*  Content-Security-Policy: frame-ancestors 'self' https://velven.ai

Remove 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.

TOML
[[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.

JSON
{  "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
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}/claim or POST /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.