Skip to content

Documentation

Where the tag goes, by platform

One script tag on your website records page reads, where each visitor came from, and the signup forms it can hear — without cookies and without touching your forms. This says where that tag goes in Webflow, Framer, WordPress, Squarespace, Carrd and Next.js, and what to do where a builder owns its forms too completely to be heard.

Six short notes, written from the founder's side, for Settings → Your website → "Where does this go?". They are rendered from PLATFORMS in src/lib/setup-prompt.ts — by PlatformNotes on the screen and by buildSetupPrompt inside the prompt below; this file is where the words are agreed and reviewed. Change one, change all three.

Each note answers two questions and nothing else: where the script tag goes, and whether the platform's own forms will take the data-kl-list attribute — because when they will not, the answer is the "Catch every signup form" switch, and the founder should be told so on the same screen rather than left to find out from an empty heartbeat.

Nothing here promises a plan a platform does not sell. Where custom code needs a paid plan, the note says so, because a founder on the free tier will otherwise paste the tag into a box that silently drops it.


Webflow

The tag. Site settings → Custom code → Head code, then publish. Custom code needs a paid site plan.

Your forms. Select the Form Block in the Designer, then Settings panel → Custom attributes → add data-kl-list with your list's name. Webflow's own form submission is untouched; Kicklace only listens.

Framer

The tag. Site settings → General → Custom code → End of <head>.

Your forms. Framer's form is its own component and will not take an attribute, so turn on Catch every signup form instead.

WordPress

The tag. The theme's header.php, or any "insert headers and scripts" plugin.

Your forms. Contact Form 7 and Gravity Forms let you edit the form's HTML, so add data-kl-list to the <form> tag there. A theme's own signup form usually does not, so use Catch every signup form.

Squarespace

The tag. Settings → Advanced → Code injection → Header. Code injection needs a Business plan or higher.

Your forms. Squarespace form blocks do not take attributes, so use Catch every signup form.

Carrd

The tag. Settings → Code → Head, on a Pro plan.

Your forms. Carrd's forms do not take attributes either, so use Catch every signup form.

Next.js, Astro, Hugo, or plain HTML

The tag. In the root layout (app/layout.tsx), either as the tag shown on the screen or as <Script src="…" strategy="afterInteractive" /> from next/script; in <head> in a plain HTML template or a static site generator's base layout.

Your forms. Add data-kl-list to your own <form> tag. If a form is submitted on the server and never reaches the browser, post to /api/v1/events from your route handler with a secret key instead — that is under "For your developers".


When the builder takes neither

Some builders own the form completely: you cannot add an attribute to it, and its submit never reaches a listener of ours, so Catch every signup form has nothing to catch either. For those, Kicklace hosts the form itself at kicklace.com/f/<workspace>/<list>. It wears the workspace's name, logo and accent, prints the list's consent sentence as the label of a box that has to be ticked, and stores that sentence with the signup — the same record a post from your own site makes. The link and the one-line <iframe> are on the list's own page in the app, under "Share a signup form".

  • Carrd. Its forms take no attributes and its own handler is closed, so link a button to the hosted form, or paste the iframe into an Embed element.
  • Framer. Its form is a component with no attribute of its own; use an Embed layer with the iframe, or point a button at the link.
  • Squarespace. Form blocks take no attributes; a Code block holds the iframe on a Business plan, and a button can carry the link on any plan.
  • Webflow, WordPress, and your own HTML. The attribute works here, so the hosted form is only for a page you would rather not touch — a landing page somebody else owns, or a link in a bio.

The form follows each visitor's own light or dark setting, which inside an iframe can leave a dark form on a light page; ?theme=light or ?theme=dark on the address pins it. It also tells whatever framed it how tall it is (postMessage, { kicklace: "height", height }) on load and again when it becomes the thank-you, so a builder that listens can size the frame; the iframe in the app carries a sensible height for one that does not.

Two things it is not. It is not a replacement for the tag: the tag is what ties a signup to the visit that led to it, and the hosted form knows only what the person typed. And it is not a way around consent — the sentence on the page is the list's own, and a signup without the tick is refused.


Or ask your AI

Working on your site with Claude Code, Cursor, Copilot, or ChatGPT? Copy this and paste it there. It carries everything: the line to add, your lists, the words people agree to, and how to check it worked.

That frame is "2. Let your AI do it" on Settings → Your website, one step above the tag since #228 — a founder building a product today has an AI open beside their site, and handing it one prompt is less work than finding the file the tag goes in. The frame also points at Settings → Claude: a workspace that has connected Claude can be asked to set the website up instead of pasting anything. The prompt behind the button is built by buildSetupPrompt in src/lib/setup-prompt.ts at render time from the workspace alone — the tag with its own public key, the addresses the workspace allows, its lists with the exact sentence each one stores, and whether it catches every signup form or only the marked ones.

Two rules hold it honest, and src/lib/__tests__/setup-prompt.test.ts keeps them:

  • Every fact comes from the workspace. Nothing is invented, and a workspace with no site or no list says so and tells the agent what to do instead of the part it cannot do yet.
  • Never a secret key. The public key is already in every page that carries the tag; a secret key belongs to a server. The prompt says so, and tells the agent to stop and tell the owner if it finds one in the site's code.

The prompt is prose in seven numbered steps — add the tag, the addresses this workspace allows, signups, forms that are not plain HTML, do not, check it worked, report back — wrapped to 78 columns so it reads wherever it is pasted. It is tool-agnostic: nothing in it names a particular agent or its file layout.