Skip to content
snagr
Snagr docs

Any app (SDK quickstart)

Recover checkouts, signups and trials in any stack with a script tag and one server call.

If you don't sell on Polar (for example you use Stripe, Paddle or your own checkout), connect Snagr with two small pieces of code: a start event when someone begins, and a finish event when they complete. If the finish never arrives, Snagr follows up.

Get your keys

Create a free account and open Developers & API keys in the sidebar. You get a publishable key (snagr_pk_…, safe in the browser) and can create a secret key (snagr_sk_…, server only).

Add the browser script

Put this in your site's <head>, before any code that calls snagr:

<script>
  window.snagr = window.snagr || { _q: [] };
  ["track", "identify", "reset", "onState"].forEach(function (method) {
    window.snagr[method] = function () {
      window.snagr._q.push([method, arguments]);
    };
  });
</script>
<script
  src="https://www.snagr.sh/sdk.js"
  data-key="YOUR_PUBLISHABLE_KEY"
  defer
></script>

Using a bundler (Next.js, Vite, …)? Install the package instead:

npm install @snagr/sdk
import { createClient } from "@snagr/sdk";

export const snagr = createClient({ key: process.env.NEXT_PUBLIC_SNAGR_KEY });

The calls below are the same either way.

Say who it is, and send the start event

On your server, sign the signed-in user's email with your secret key, and pass only the result (emailHash) to the browser:

import { createHmac } from "node:crypto";

const emailHash = createHmac("sha256", process.env.SNAGR_SECRET_KEY)
  .update(user.email.trim().toLowerCase())
  .digest("hex");

Then in the browser, when checkout starts:

snagr.identify({ email: user.email, userId: user.id, emailHash });
snagr.track("checkout_started", { url: resumeUrl, revenue: 49 });

url is where the reminder email links back to, so make it a page that can resume the checkout.

Send the finish event from your server

After your payment webhook confirms the payment:

await fetch("https://www.snagr.sh/api/v1/batch", {
  method: "POST",
  headers: {
    Authorization: "Bearer " + process.env.SNAGR_SECRET_KEY,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    batch: [
      {
        type: "track",
        email: customer.email,
        event: "purchase_completed",
        messageId: order.id,
        properties: { revenue: order.amount / 100, currency: "USD" },
      },
    ],
  }),
});

revenue is in normal currency units (49, not 4900). messageId stops a retried webhook from counting twice.

Turn on a flow

In Flows, pick the Started checkout, didn't buy recipe. Check the event names, edit the email, send yourself a test, then switch it on.