Documentation

Webhooks

Real-time event notifications

Overview

Webhooks let you receive real-time HTTP notifications when events occur in your Loamly workspace. Use webhooks to:

  • Sync data to your CRM when a visitor converts
  • Trigger Slack notifications for high-intent visitors
  • Update your database when new AI mentions are detected
  • Build custom integrations with your internal tools

Setting up webhooks

  1. Go to your dashboard → Settings Webhooks
  2. Click Add Webhook
  3. Enter your endpoint URL (must be HTTPS)
  4. Select the events you want to receive
  5. Click Create Webhook
  6. Copy the signing secret for verification

HTTPS required

Webhook endpoints must use HTTPS. We do not send webhooks to HTTP URLs for security reasons.

Available events

EventDescription
visitor.createdA new visitor arrived on your site
visitor.convertedA visitor submitted a form or completed a conversion goal
visitor.identifiedA visitor's email was captured
mention.createdA new AI mention of your brand was detected
mention.attributedAn AI mention was linked to a website visit
payment.receivedA Stripe payment was attributed (requires Stripe integration)

Webhook payload

All webhooks are sent as POST requests with a JSON body:

{
  "id": "evt_abc123xyz",
  "type": "visitor.converted",
  "created_at": "2024-12-18T14:30:00Z",
  "data": {
    "visitor_id": "vis_xyz789",
    "source": "chatgpt",
    "intent": "active_purchase_intent",
    "email": "user@example.com",
    "form_name": "Contact Form",
    "page_url": "https://example.com/pricing",
    "conversion_value": null
  }
}

Event-specific payloads

visitor.created

{
  "id": "evt_...",
  "type": "visitor.created",
  "data": {
    "visitor_id": "vis_...",
    "source": "perplexity",
    "referrer": "https://perplexity.ai/...",
    "landing_page": "/",
    "country": "US",
    "city": "New York",
    "device": "desktop",
    "browser": "Chrome"
  }
}

mention.created

{
  "id": "evt_...",
  "type": "mention.created",
  "data": {
    "mention_id": "mnt_...",
    "platform": "chatgpt",
    "query": "best SaaS analytics tools",
    "position": 3,
    "sentiment": "positive",
    "competitors": ["Mixpanel", "Amplitude"]
  }
}

Verifying webhooks

Every webhook includes a signature header for verification. Always verify signatures to ensure requests come from Loamly.

Signature header

X-Loamly-Signature: t=1703001234,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd

Verification steps

  1. Extract the timestamp and signature from the header
  2. Prepare the signed payload (timestamp + "." + request body)
  3. Compute HMAC-SHA256 with your signing secret
  4. Compare the computed signature with the received signature
  5. Check that the timestamp is within 5 minutes of current time

Example: Node.js

import crypto from 'crypto';

function verifyWebhook(payload, signature, secret) {
  const [timestampPart, signaturePart] = signature.split(',');
  const timestamp = timestampPart.split('=')[1];
  const expectedSig = signaturePart.split('=')[1];

  // Check timestamp is recent (5 min tolerance)
  const now = Math.floor(Date.now() / 1000);
  if (Math.abs(now - parseInt(timestamp)) > 300) {
    throw new Error('Webhook timestamp too old');
  }

  // Compute expected signature
  const signedPayload = `${timestamp}.${payload}`;
  const hmac = crypto.createHmac('sha256', secret);
  hmac.update(signedPayload);
  const computedSig = hmac.digest('hex');

  // Compare signatures (timing-safe)
  if (!crypto.timingSafeEqual(
    Buffer.from(expectedSig),
    Buffer.from(computedSig)
  )) {
    throw new Error('Invalid webhook signature');
  }

  return JSON.parse(payload);
}

Always verify signatures

Never trust webhook payloads without verifying the signature. Attackers could send fake webhooks to your endpoint.

Retry behavior

If your endpoint returns a non-2xx status code or times out, Loamly retries the webhook with exponential backoff:

AttemptDelay
1Immediate
21 minute
35 minutes
430 minutes
52 hours

After 5 failed attempts, the webhook is marked as failed and no longer retried.

Best practices

  • Return 200 quickly. Process webhooks asynchronously after acknowledging receipt.
  • Handle duplicates. Use the event ID to deduplicate in case of retries.
  • Log failed webhooks. Check the Webhooks page in Settings for delivery history.