Tracking Pixels and Webhooks: The DIY Sales Pipeline Nobody Talks About
Most indie hackers obsess over landing pages and SEO. Meanwhile, the most useful thing I built for my web dev business was a tracking pixel and a webhook.
Here's the setup: I find local businesses with outdated websites, generate a modern mockup, and send them a link. Simple enough. But the magic isn't in the outreach — it's in knowing what happens after the message lands.
The Tracking Pixel
Every mockup link includes a ?ref=PROSPECT_ID parameter. When someone clicks through, a lightweight endpoint logs the visit:
// Convex HTTP action
export const track = httpAction(async (ctx, request) => {
const url = new URL(request.url);
const ref = url.searchParams.get("ref");
if (ref) {
await ctx.runMutation(api.prospects.recordView, { id: ref });
}
// Return a 1x1 transparent pixel
return new Response(PIXEL, {
headers: { "Content-Type": "image/gif" },
});
});
Now I know exactly who opened the link, when, and how many times. A prospect who visits their mockup three times in two days is a warm lead. Someone who never clicks? Don't waste a follow-up.
The Webhook Loop
The tracking pixel fires a mutation that updates the prospect record. But it also triggers a webhook back to my AI agent (running on OpenClaw). The agent sees the view event and can autonomously decide what to do:
- First view → add a note: "👀 Prospect viewed their redesign"
- Multiple views in 24h → flag as hot lead
- View + no response after 48h → queue a gentle follow-up
This creates a closed loop. The outreach goes out, the tracking pixel reports back, and the agent adapts. No dashboard refreshing. No manual CRM updates.
Why This Beats SaaS Tools
You could use HubSpot or Salesforce for this. But for a solo operation:
- Cost: My entire stack runs on a $10/month VPS. Convex is self-hosted. The tracking endpoint is three lines of code.
- Control: I own the data. I can query it however I want. No vendor lock-in, no monthly seat fees.
- Integration: Because the webhook hits my AI agent directly, I can do things no SaaS tool supports — like having the agent draft a personalized follow-up based on which sections of the mockup the prospect spent time on.
The Stripe Shortcut
I added one more piece: a Stripe payment link generator. When a prospect is flagged as warm, the system creates a $200 payment link specific to that prospect:
export const createPaymentLink = action(async (ctx, args) => {
const session = await stripe.checkout.sessions.create({
line_items: [{ price: PRICE_ID, quantity: 1 }],
mode: "payment",
metadata: { prospectId: args.prospectId },
success_url: ${BASE_URL}/thank-you?ref=${args.prospectId},
});
return session.url;
});
The follow-up message includes the payment link. Prospect clicks mockup → views redesign → gets follow-up with payment link → pays. Four steps, mostly automated.
What I Learned
Tracking changes behavior. Before the pixel, I'd send 20 messages and wonder why nobody responded. After, I realized most people were clicking — they just needed a nudge. The data turned a 2% response rate into 15%.
Webhooks are underrated glue. Everyone talks about APIs. But a simple webhook that says "this thing happened" and lets your agent decide what to do next is incredibly powerful. It's event-driven architecture without the enterprise overhead.
You don't need much. A Convex backend, a tracking pixel, a webhook, and an AI agent. Total code: maybe 200 lines. Total cost: nearly zero. But it gave me a sales pipeline that adapts in real time.
The best tools aren't the ones with the most features. They're the ones you build yourself, because they do exactly what you need and nothing else.