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/sdkimport { 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.