One script. Any prototype.

Install Pinmark on your prototype

The setup is always the same. Choose your platform to see exactly where the snippet belongs.

  1. 01
    Create a project. Open the dashboard and copy your snippet.<script async src="https://pinmark-gamma.vercel.app/w.js" data-pinmark="pk_live_YOUR_KEY"></script>
  2. 02
    Allow the domain. Add your prototype's domain (for example myproto.vercel.app) to Allowed domains. Include localhost for local testing.
  3. 03
    Paste and publish. Add the snippet to the <head>. The comment bubble appears bottom-right; press C or drag to comment on an area.

Framework + hosting

Next.js / Vercel

Using an AI code assistant? Give it the project-aware prompt below:

Prompt for your coding agent
Install Pinmark in this project so it loads on every page.

1. Detect how this app manages its document <head>.
2. For Next.js App Router, add the script in app/layout.tsx. For Pages Router, add it in pages/_document.tsx. For another framework, use its shared document or root layout.
3. Add the script exactly once and keep async and data-pinmark unchanged.
4. Do not change unrelated code.

Use this script:
<script async src="https://pinmark-gamma.vercel.app/w.js" data-pinmark="pk_live_YOUR_KEY"></script>

Afterward, tell me which file you changed.

App Router: in app/layout.tsx, add the script inside <head>:

<head> <script async src="https://pinmark-gamma.vercel.app/w.js" data-pinmark="pk_live_YOUR_KEY"></script> </head>

Pages Router: add it inside <Head> in pages/_document.tsx.

Allowed domain: your-app.vercel.app plus any custom domain. Preview deployments get a unique subdomain per deploy; add those individually if you review previews.

AI app builder

Lovable

Fastest path is asking the AI:

Add this script tag to the <head> of index.html and change nothing else: <script async src="https://pinmark-gamma.vercel.app/w.js" data-pinmark="pk_live_YOUR_KEY"></script>

Or in Dev Mode, edit index.html yourself and paste before </head>. Then publish.

Allowed domain: your-app.lovable.app, or *.lovable.app to cover renames and previews.

Site builder

Webflow

paid site plan required
  1. Site settings → Custom Code
  2. Paste the snippet into Head Code
  3. Save, then publish the site

Custom code only runs on sites with a paid plan; free *.webflow.io staging sites won't inject it. For a single page, use Page Settings → Custom Code instead. Allowed domain: your-site.webflow.io or your custom domain.

Site builder

Framer

paid site plan required
  1. Site Settings → General Custom Code
  2. Paste into Start of <head> tag
  3. Publish

Allowed domain: your-site.framer.app, *.framer.website, or your custom domain.

Cloud IDE

Replit

  1. Edit your app's index.html (project root, or client/ in full-stack templates)
  2. Paste before </head>
  3. Redeploy from the Deployments tab

Allowed domain: your-app.replit.app. Replit's AI agent can also add the tag for you.

AI app builders

Bolt / v0

Same prompt pattern as Lovable:

Add this script tag to the document <head> and change nothing else: <script async src="https://pinmark-gamma.vercel.app/w.js" data-pinmark="pk_live_YOUR_KEY"></script>

For v0's Next.js output it belongs in app/layout.tsx. Allowed domain: whatever your deployment's address bar shows.

Hosting

Netlify

Paste into your site's HTML like any static site, or inject without touching code: Site configuration → Build & deploy Post processingSnippet injection → "Insert before </head>".

Allowed domain: your-site.netlify.app or your custom domain.

Universal install

Plain HTML

For a custom-coded site, this prompt finds the shared document and installs Pinmark once:

Prompt for your coding agent
Install Pinmark on every page of this site.

Add the script below exactly once to the shared document <head>, immediately before </head>. If the site uses templates or layouts, choose the root layout that renders every page. Keep async and data-pinmark unchanged, and do not change unrelated code.

<script async src="https://pinmark-gamma.vercel.app/w.js" data-pinmark="pk_live_YOUR_KEY"></script>

Afterward, tell me which file you changed.

Paste anywhere in the page, before </head> by convention. It loads async and never blocks or breaks the host page.

<script async src="https://pinmark-gamma.vercel.app/w.js" data-pinmark="pk_live_YOUR_KEY"></script>

Works on GitHub Pages, Cloudflare Pages, Render, S3, your own server, any framework. The only requirements: the page's domain is on your allowlist and can reach https://pinmark-gamma.vercel.app.

Site builders

Wix / Squarespace

paid plans required

Wix: Settings → Custom Code → Add Custom Code → apply to All Pages, load in Head.

Squarespace: Settings → Advanced → Code Injection → Header field.

Wix needs Premium; Squarespace needs Business or higher.

Own every layer

Self-hosting

Pinmark is open source under the MIT license.

Running your own instance means bringing your own Supabase project (cloud free tier, or self-hosted Supabase) and deploying apps/web anywhere Node runs. Full steps for environment variables, auth redirect URLs, and a smoke test are in DEPLOY.md.

Quick diagnostics

Troubleshooting

No bubble? Open the browser console and find the [pinmark] line; it names the exact problem:

Pins shift after resizing? Pins dropped on empty background have nothing to attach to and fall back to page-relative position (shown at 60% opacity). Pin on concrete elements, buttons, cards, headings, for positions that survive any viewport.

Stale behavior after changing settings? w.js is cached for five minutes; hard reload (Cmd+Shift+R) picks changes up immediately.