Skip to content

Developers

Growth infrastructure you configure with AI and run with one line.

One record per person from the first visit to the purchase, consent stored word for word, and follow-up that runs by itself.

One line in your server

Install the package, pass it a secret key, and post what a person did. It has no dependencies, it runs anywhere fetch does, and it never throws.

Install
npm install kicklace
Your server
import { Kicklace } from "kicklace";

const kl = new Kicklace(process.env.KICKLACE_SECRET_KEY!);

await kl.track("signup", { email });
await kl.track("purchase", { email, value: 49, idempotencyKey: invoice.id });
await kl.track({ type: "credit_added", accountId, properties: { credits: 10 } });

Kicklace's own names are pageview, signup, download, activated and purchase. A name of your own, like credit_added, lands on the person's timeline and an automation can answer it.

A refusal is an answer
type Outcome =
  | { ok: true; status: string; id?: string }
  | {
      ok: false;
      error: string;
      message: string;
      httpStatus: number;
    };

Every method resolves, and TypeScript makes you look at ok. error is Kicklace's own code and message is its own sentence, handed on untouched, because the fix is usually inside it. Nothing this package does can throw inside your checkout.

A 5xx and a network failure are tried again; a 4xx never is, because a refusal will not change. Give anything that must land exactly once an idempotencyKey — it is what makes a retried purchase, ours or your own webhook's, land once.

Who they are, and what they agreed to
await kl.identify({ email, anonId, name, fields: { phone } });

await kl.subscribe({
  email,
  list: "product-updates",
  consent: "Send me product updates. I can unsubscribe with one click.",
});

await kl.batch([
  { type: "pageview", anonId },
  { type: "identify", email, anonId },
]);

A subscription needs the words the person read. subscribe stores that sentence verbatim as the proof, with the day and, if you send it, their IP; without one it is refused. The browser id from the tag is anonId, which is how the visitor who read the pricing page last week and the customer who paid today are one record.

The tag on your site

The events API is what your server knows. The tag is what your website knows: page reads, where somebody came from, and the signup forms it can hear.

Next.js · app/layout.tsx
import { KicklaceTag } from "kicklace/next";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        {children}
        <KicklaceTag />
      </body>
    </html>
  );
}
Anything else
<script
  async
  src="https://www.kicklace.com/api/in/YOUR_KEY/track.js">
</script>

The tag takes your public key, wk_…, which is meant to be in a page. Your secret key, sk_live_…, belongs on a server and never in browser code: handed one, <KicklaceTag /> renders nothing and says why in the console. Both keys are under Settings → Your website.

It keeps one random id in the browser's own storage, reads the campaign a visitor arrived on, and can hear your signup forms without touching them. No cookies.

What arrives by itself

Some of what a person does, nobody has to send. Connect the door and it lands as the same event your own code would have posted.

Stripe
Payments, refunds and subscriptions, without a handler of your own. A paid invoice becomes a purchase with its amount on the person's timeline, and the lifecycle moves to Purchaser. Paste one address into Stripe and bring back the signing secret.
Clerk and Kinde
Sign-ups and sign-ins from the accounts you already have. A new account becomes a person with the lifecycle moved to Account, and a later event with no email address still finds them. One address pasted in, and there is no code to write.
Vercel
Deployments, as releases. A production deploy becomes a Release on its own board, and an automation can draft the changelog email from it for you to send. Paste one address into Vercel's webhooks and bring back the secret. Vercel has no webhook for visitors; the tag is what sees them.
Your own servers
The package is a wrapper over POST /api/v1/events, so anything it does you can post by hand with a secret key: events, identify, subscribe and support messages, single or in a batch, each with an idempotency key and an expiry date if you promise one.
Outgoing webhooks
What Kicklace tells your code. Every trigger — a stage entered, a subscription, a reply — is posted to your address with a X-Kicklace-Signature header signed with your own secret, and tried again when your server is down.

Configure it with Claude

The other half of Kicklace is the configuration layer: point Claude at your workspace and set it up by asking.

Settings → Claude connects it: sign in from Claude, or take a key for another client. From there Claude can look people up, add them, write notes and tasks, make the lists, templates, stages, fields, views and charts your events then feed, and draft an automation for you to read and turn on.

“Set up a Product updates list and write the welcome email for it”

  • It never sends an email. It writes the draft and hands you the link.
  • It never deletes a record, and it never puts anyone on a list without the words they agreed to.
  • Everything it does is in your name, and written down on that same screen.

What you stop maintaining

The parts a small team wires together by hand, and what each one becomes.

A webhook handler that updates a users table
Stripe posts to Kicklace instead. The payment lands on the person who made it, and their stage moves with it.
An events table nobody reads
The timeline is that table, and it is the same record your follow-up runs on and your charts count.
A mailing tool with its own copy of the same people
Lists live on the record, with the sentence each person agreed to stored word for word and a one-click unsubscribe in every email.
A spreadsheet of sign-ups
Contacts, with saved views, a board, and an export whenever you want one.
The glue between them
One record per person, from the anonymous first visit to the purchase, across devices. There is nothing left to match up afterwards.

Join the waitlist

We are onboarding one company at a time. Leave your email and we will let you know when your workspace is ready.

Optional.

Optional. Tell us about your product and where your leads come from.

Which plan would you want?

Prices are not final and nothing is charged. Pick a plan now and you will get that price when billing opens.

By joining, you agree to receive waitlist updates from Kicklace: Put me on the Kicklace waitlist and tell me when a workspace can open for my company. We store this wording with the date and your email address. Every email has a one-click unsubscribe link. Privacy policy.

We reply to every signup.

Billing is not live yet, and nothing is charged. Early customers use Kicklace free while we build it with them.