Push GitHub Developer Leads to Loops

Send GitLeads developer signals into Loops.so contacts and email sequences automatically. Route GitHub stargazer and keyword leads to your SaaS email tool via webhook.

Published: May 8, 2026Updated: May 8, 20266 min read

Why Loops for Developer Leads

Loops.so is an email platform built specifically for SaaS companies and developer tools. Unlike general-purpose marketing tools, Loops treats transactional and marketing email as one unified system, with a developer-first REST API and a contact model centered on user activity events rather than static lists. When a developer stars your competitor's repo or mentions your category keyword in a GitHub discussion, Loops lets you trigger a targeted email sequence immediately — no manual import, no batch delays.

How the Data Flows

GitLeads fires a JSON webhook for every captured lead. That payload carries the developer's GitHub profile data plus the signal context. Your handler reads it, creates or updates a Loops contact, then sends a Loops event to trigger a sequence. The contact record stores GitHub-enriched attributes — username, company, top languages, signal type — that you can reference in email personalization.

// Node.js handler: GitLeads webhook → Loops contact + event
import express from 'express';
import crypto from 'crypto';

const app = express();
app.use(express.json());

const LOOPS_API_KEY = process.env.LOOPS_API_KEY!;
const GITLEADS_SECRET = process.env.GITLEADS_WEBHOOK_SECRET!;

function verify(sig: string, body: string): boolean {
  const expected = crypto.createHmac('sha256', GITLEADS_SECRET).update(body).digest('hex');
  return crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected));
}

app.post('/webhook/gitleads', express.raw({ type: 'application/json' }), async (req, res) => {
  const sig = req.headers['x-gitleads-signature'] as string;
  if (!verify(sig, req.body.toString())) return res.status(401).send('invalid signature');

  const lead = JSON.parse(req.body.toString()) as {
    github_username: string;
    name: string;
    email: string;
    company: string;
    top_languages: string[];
    followers: number;
    signal: { type: string; keyword?: string; repo: string; context: string };
  };

  // Skip leads with no email — Loops requires an email address
  if (!lead.email) return res.send('no email, skipped');

  // Step 1: create or update the contact in Loops
  await fetch('https://app.loops.so/api/v1/contacts/update', {
    method: 'PUT',
    headers: { Authorization: `Bearer ${LOOPS_API_KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      email: lead.email,
      firstName: (lead.name || lead.github_username).split(' ')[0],
      lastName: (lead.name || '').split(' ').slice(1).join(' ') || undefined,
      company: lead.company || undefined,
      // Custom contact properties for personalization in email copy
      githubUsername: lead.github_username,
      githubFollowers: lead.followers,
      topLanguage: lead.top_languages?.[0] || undefined,
      signalType: lead.signal.type,
      signalRepo: lead.signal.repo,
      signalKeyword: lead.signal.keyword || undefined,
      source: 'gitleads',
    }),
  });

  // Step 2: send a Loops event to trigger the right sequence
  // Create separate Loops events per signal type for targeted sequences
  const eventName = lead.signal.type === 'stargazer'
    ? 'github_stargazer_captured'
    : 'github_keyword_captured';

  await fetch('https://app.loops.so/api/v1/events/send', {
    method: 'POST',
    headers: { Authorization: `Bearer ${LOOPS_API_KEY}`, 'Content-Type': 'application/json' },
    body: JSON.stringify({
      email: lead.email,
      eventName,
      // Event properties available as variables inside Loops email templates
      eventProperties: {
        signal_context: lead.signal.context.slice(0, 500),
        signal_repo: lead.signal.repo,
        signal_keyword: lead.signal.keyword,
      },
    }),
  });

  res.send('ok');
});

app.listen(3000);

Setting Up in GitLeads

  1. In your GitLeads dashboard go to Settings → Integrations → Webhook
  2. Enter your endpoint URL and copy the signing secret into GITLEADS_WEBHOOK_SECRET
  3. Generate a Loops API key at app.loops.so → Settings → API — store as LOOPS_API_KEY
  4. Create two Loops events in the Loops dashboard: github_stargazer_captured and github_keyword_captured
  5. Attach email sequences to each event — stargazers get a sequence explaining your product, keyword signals get a more targeted message referencing the problem they mentioned

Personalizing the Emails

Loops email templates use Handlebars-style variables. Because you stored GitHub data as contact properties, your subject line can reference them: "Hey {{firstName}}, saw you're working with {{topLanguage}}" or "Noticed you starred {{signalRepo}} — here's how [product] fits." The signal_context event property lets you reference the exact GitHub issue or PR text that triggered the capture, making outreach feel like a direct response rather than a cold email.

Handling Leads Without Public Emails

Many GitHub profiles do not have a public email. GitLeads includes email when available. For leads without email, the above handler skips the Loops contact creation. Common patterns for these leads: route them to Clay for enrichment (which can find work emails from company + name), or push them to Slack for manual review by DevRel. You can also use Loops with verified email from enrichment downstream.

Route GitHub developer signals into Loops email sequences automatically. Start free at [gitleads.app](https://gitleads.app). Related: [push GitHub leads to webhook](/blog/push-github-leads-to-webhook), [push GitHub leads to Clay](/blog/push-github-leads-to-clay), [push GitHub leads to Customer.io](/blog/push-github-leads-to-customer-io).

Want more like this? Get the weekly developer lead playbook.

No spam. 5 emails over 2 weeks. Unsubscribe anytime.

Related Articles

How to Find Leads on GitHub: The Complete Guide (2026)
10 min read
GitHub Leads vs LinkedIn Leads: When to Use Which (2026)
9 min read
GDPR Compliance for GitHub Lead Scraping: What You Must Know
8 min read