Everything from "drop the snippet" to reading your first leads — plus signed webhooks for pushing leads into your own tools.
Add this single line of JavaScript to your site's <head> tag.
<script src="https://clickmemaybe.com/cmm/YOUR_SITE_KEY.js" defer></script>
Replace YOUR_SITE_KEY with the site key from your Websites page — or just copy the ready-made snippet from the site's Manage page.
We support direct installation in WordPress (via plugin), Shopify (via theme.liquid), Webflow, Squarespace, and any custom HTML or React/Vue/Svelte SPA.
Open your site, then come back to the dashboard. Your site card should show "Live" within 30 seconds.
Pick a category, drop in your headline and CTA, and pick which site to show it on. You can refine targeting and design later.
popup
live
sticky_bar
live
floating_cta
live
form
soon
exit_intent
live
countdown
live
social_proof
live
announcement
soon
callback
live
slide_in
live
fullscreen
soon
multi_step
soon
cookie_consent
soon
sticky_atc
soon
spin_to_win
soon
survey
soon
back_in_stock
soon
age_gate
soon
video_popup
soon
live_visitors
soon
Each widget supports your brand colors, fonts, and a custom CSS escape hatch.
Show a widget only on selected paths (exact path such as /pricing, or a prefix such as /blog/*) and exclude paths where it must never appear. Exclusions win. Rules match the page path, not the query string.
Target all devices, desktop only, or mobile only (viewports narrower than 768px). Geo, language, returning visitors, referrer and UTM targeting are on the roadmap.
Each widget type has a built-in trigger: on-load popups appear shortly after the page is ready, exit-intent popups fire when the cursor leaves the viewport (timer + scroll-up on touch devices), bars and floating buttons render immediately. Scroll-depth, time-on-page and custom-event triggers are on the roadmap.
We track impressions (widget rendered), clicks (interaction), and submissions (form completion). Custom events coming soon.
Leads land in your inbox in real time. Mark them new, reviewed, or contacted, and export as CSV anytime.
List and create widgets, query analytics, and pull leads — all over a clean REST API.
Get every new lead pushed to your own endpoint the moment it arrives. Open your website → Install → Security, paste an https:// URL and save. A signing secret is generated and shown once — store it.
We send a POST with a JSON body and these headers:
Content-Type: application/json X-CMM-Event: lead.created X-CMM-Signature: sha256=<hex HMAC-SHA256 of the raw body, keyed with your secret> User-Agent: ClickMeMaybe-Webhook/1.0
lead.created{
"event": "lead.created",
"created_at": "2026-09-03T10:15:42+00:00",
"lead": {
"id": 1234,
"email": "anna@example.com",
"phone": null,
"name": "Anna",
"page": "https://yoursite.com/pricing",
"device": "mobile",
"type": "optin"
},
"widget": { "id": 42, "name": "Exit popup — yoursite.com", "category": "exit_intent" },
"website": { "id": 7, "domain": "yoursite.com" }
}
lead.type is one of callback, message, optin, contact (falls back to the widget category). Fields that don't apply are null.
lead.id as the idempotency key: a retry may re-send the same lead.Always compute the HMAC over the raw request body (before JSON parsing) and compare in constant time.
$secret = getenv('CMM_WEBHOOK_SECRET');
$body = file_get_contents('php://input');
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
$given = $_SERVER['HTTP_X_CMM_SIGNATURE'] ?? '';
if (! hash_equals($expected, $given)) {
http_response_code(401);
exit('bad signature');
}
$event = json_decode($body, true);
// $event['lead']['email'] ...
http_response_code(204);
import crypto from 'node:crypto';
import express from 'express';
const app = express();
const SECRET = process.env.CMM_WEBHOOK_SECRET;
// Keep the raw body — the signature is computed over the exact bytes we sent.
app.post('/cmm-webhook', express.raw({ type: 'application/json' }), (req, res) => {
const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(req.body).digest('hex');
const given = req.get('X-CMM-Signature') || '';
if (expected.length !== given.length || !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(given))) {
return res.status(401).send('bad signature');
}
const event = JSON.parse(req.body.toString('utf8'));
// event.lead.email ...
res.sendStatus(204);
});
Rotating the secret (Regenerate secret in Security) invalidates the old one immediately — update your endpoint first, then rotate.
No native app needed. In Zapier create a Zap with the trigger Webhooks by Zapier → Catch Hook, copy the generated URL and paste it as your webhook URL in Security. Send a test lead from your widget, then map lead.email, lead.name etc. into any of 5,000+ apps. The same works with Make (Custom webhook) and n8n (Webhook node).
Install in 5 minutes. Publish your first widget today.
Start Free Now