Self-hosted ad attribution, revenue ledger and CRM. See which ad actually made you money. Free to self-host, source available (FSL-1.1).
See the code
See which ad actually made you money, what that customer really cost, and prove it.
Self-hosted ad attribution, revenue ledger and CRM.
Free to self-host. Source available (FSL-1.1). Your server, your data.
AdLedger joins ad spend (Meta, Google and 7 more networks), website events from a 2.4 KB pixel, leads and real payments (Stripe and 12 more) into one ledger, so every number is computed in SQL, split to the cent and shown per campaign, ad set and ad. One container plus PostgreSQL, on a server you control.
Not sure yet? Take the 3D product tour, or run the demo below with 90 days of sample data.
Free to self-host, with the source on GitHub. No per-seat or revenue-share pricing. Unlimited users, workspaces and client logins.
Your data never leaves your server. No telemetry, no licence check, no phone-home.
You need Docker. This starts AdLedger with 90 days of demo data:
git clone https://github.com/ShubhamVankalas/adledger.git && cd adledger
ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=adledger-demo-123 DEMO_DATA=true docker compose up -d
Open http://localhost:3000 and sign in. The demo runs on mock connectors that speak each platform's
real API format (Meta, Google, TikTok, LinkedIn, Microsoft, Stripe). Or run plain docker compose up -d,
create your account and choose Explore with demo data.
$env:ADMIN_EMAIL="admin@example.com"; $env:ADMIN_PASSWORD="adledger-demo-123"; $env:DEMO_DATA="true"
docker compose up -d
Point an A record at the server, open ports 80 and 443, then:
curl -fsSL https://raw.githubusercontent.com/ShubhamVankalas/adledger/main/install.sh | DOMAIN=ads.yourcompany.com sh
The script installs nothing but AdLedger: it downloads docker-compose.yml, writes a .env with
generated secrets, and starts the app, PostgreSQL 16 and Caddy. Re-run it to upgrade.
| Where | How |
|---|---|
| Render | render.yaml: web service, managed PostgreSQL 16 and a generated APP_SECRET. |
| Railway | Deploy from your fork (uses the Dockerfile and railway.json), add PostgreSQL, set DATABASE_URL=${{Postgres.DATABASE_URL}}. |
| Coolify, Dokploy, CapRover, Portainer | Deploy docker-compose.yml as-is. |
| Single container, no PostgreSQL | docker run -d -p 3000:3000 -v adledger:/data ghcr.io/shubhamvankalas/adledger (embedded database; fine for trials, use PostgreSQL for production). |
pnpm install && pnpm dev # http://localhost:3000, embedded database in ./.data
Upgrade with docker compose pull && docker compose up -d. Backups, HTTPS and every setting:
docs/SELF_HOSTING.md.
![]() |
The Overview is a widget board. Press Customize (or
|
|
Visitors on your site right now, today vs the same time yesterday, and a real-time feed of ad clicks, visits, leads, payments and refunds (server-sent events, no extra service).
| ![]() |
![]() |
Campaigns, ad sets and ads with column presets, NC-ROAS, a platform gap column (what the platform reports next to what AdLedger verified), a quadrant that sorts campaigns into scale, test, fix and kill, and saved views with a peek into the people a campaign brought in. |
|
First touch, last touch and linear, switchable anywhere, with exact integer-cent splits that always add up to the payment. Paths shows the journeys customers took, Time to convert shows whether your attribution window is long enough, and unattributed revenue is always shown, never hidden. | ![]() |
![]() |
Customers: LTV and cohorts. Lifetime value by acquiring channel, LTV:CAC and a cohort heatmap by first-payment month (retention, cumulative LTV or revenue), with a dot where each cohort paid back its CAC. Renewals are credited to the journey that first acquired the customer. |
|
Ad Receipts. Every payment shows which ads earned it, what that customer cost in ad spend and when they paid it back. Customer costs plus unallocated equal total spend, to the cent.
|
Profit Ledger. Enter cost of goods, payment fees and shipping once. Get contribution, profit after ads, POAS, break-even ROAS and a P&L waterfall, plus which ads bring buyers who refund.
|
|
Truth Gap. "Meta says its ads made you this much; real payments from people who clicked them were that much." Claimed vs verified conversions and value per platform and campaign. |
Too-early guardrails. Median and p80 days from first click to first payment, a "too early to judge" tag on young campaigns, and pause drafts you download as a Meta or Google Ads Editor file. AdLedger never writes to your ad accounts. |
![]() Contacts. Saved views, filters, groups, bulk actions with undo, fast at 10k+ contacts. | ![]() Record page. Ad clicks, visits, forms and payments on one timeline, plus notes, tasks and attribution. | ![]() Pipeline. Drag by mouse, touch or keyboard. Payments move contacts to Won automatically. |
Also: My tasks, CSV import with a preview before anything is written, and duplicate review and merge with re-attribution.
![]() |
Eleven print-ready PDF reports: executive summary, weekly performance, attribution model comparison, LTV and cohorts, wasted spend, channel mix, lead source quality, creative and ad leaderboard, funnel and time to convert, pipeline and CRM activity and profit and refunds. Your logo on the masthead, a methodology appendix, a "Prepared for" watermark and a fingerprint on every
page that anyone can check at |
AI document generator. Pick one of 12 prompt templates (monthly client report, board update, post-mortem, budget memo, Meta vs Google, lead quality audit, stand-up, case study, creative brief, quarter review, funnel leaks, refunds) or write your own. Your model writes the words; AdLedger draws every KPI, table and chart from SQL, removes any sentence with a number that is not in the data, and lays it out as a branded, fingerprinted PDF with an in-app preview.
|
Action cards (move budget, room to grow, revenue drop, CAC up) where every figure links to its source row, a weekly report marked All numbers verified, and Ask: plain-language questions answered from read-only SQL tools, with the table each answer came from. Any number a model invents is flagged. Works with no model at all, a local model (Ollama, LM Studio) or OpenAI, Anthropic, Gemini, OpenRouter, DeepSeek and any OpenAI-compatible endpoint. | ![]() |
G then a letter jumps between pages; ? lists shortcuts.
A dedicated Developers area (owners and admins by default) for wiring AdLedger into your own tools:
reports:read, mcp, contacts:read, contacts:pii, ingest:write), optional expiry, stored hashed.lead.created, contact.created, contact.updated, payment.succeeded
and payment.refunded: HMAC-SHA256 signatures, retries with backoff for about two days, a 30-day delivery
log with redeliver, Send test event, masked emails unless you opt in, private URLs blocked.
docs/WEBHOOKS.md# Pull leads with a read key
curl -H "Authorization: Bearer al_..." https://your-adledger/api/v1/leads
Ask Claude, Cursor or any MCP client "which ads made money last month?" against your own ledger. Create a key in Developers → API keys, then:
claude mcp add --transport http adledger https://your-adledger/api/mcp --header "Authorization: Bearer al_..."
get_overview, get_performance, find_wasted_spend, compare_periods, get_platform_breakdown,
get_timeseries, search_campaigns, contact_stage_funnel, list_contacts, get_contact_journey,
get_ad_receipt, get_latest_insights, get_sync_status, list_integrations.
Every tool is annotated read-only and a test proves none of them changes data. Emails are masked. Setup for Claude Desktop and Cursor: docs/MCP.md.
Connected from Settings → Integrations, with step-by-step instructions on each card and a mock mode for every connector.
| Ad platforms | Meta Ads, Google Ads, Microsoft Ads, TikTok Ads, LinkedIn Ads, Pinterest Ads, Snapchat Ads, Reddit Ads, X Ads. Anything else by CSV or the Spend API. |
| Payments and stores | Stripe (paste one key, the webhook is created for you), Shopify, WooCommerce, Paddle, Lemon Squeezy, Razorpay, PayPal, Chargebee, Recurly, Gumroad, Cashfree, Instamojo, PhonePe. Anything else by CSV or the Conversions API. |
| CRMs | Won deals from HubSpot and Pipedrive. |
| Lead forms | Any form with data-adledger-lead, Typeform, Tally, Webflow, Zapier or Make webhooks, native Meta Lead Ads, Google Ads lead forms, TikTok Lead Generation and WhatsApp click-to-chat. |
| Your website | One <script> tag (2.4 KB gzipped), a WordPress/WooCommerce plugin, a Shopify custom pixel, a GTM template and guides for Webflow, Wix, Squarespace, Framer and Next.js. |
| Back to the ad platforms (beta) | Consent-aware conversion upload to the Meta Conversions API and Google Ads, hashed identifiers only. |
| Notifications | Email, Slack, Discord, Microsoft Teams, SMS (Twilio), signed webhook. |
Connectors other than Meta, Google Ads and Stripe are in beta: tested against real-format fixtures, not yet verified on live accounts. Details: docs/CONNECTORS.md.
| Overview | Revenue and ROAS by attribution model |
|---|---|
![]() | ![]() |
| Time to convert | Time to money and pause drafts |
![]() | ![]() |
| Ask your numbers | Security policy and posture checklist |
![]() | ![]() |
| 30+ integrations | Guided setup checklist |
![]() | ![]() |
| Tracking snippet and consent modes | Members and roles |
|---|---|
![]() | |
| Alert rules and anomaly detection | Hash-chained audit log |
![]() | ![]() |
| Two-factor sign-in and devices | Notification channels |
![]() | ![]() |
| Verify a PDF report | |
![]() |
On your phone: installable as an app, with a floating tab bar and a one-tap filter sheet.
AdLedger is self-hosted software, so it holds no certification and makes no compliance claim on your behalf. It ships GDPR-ready tooling and SOC 2-aligned controls to help you meet GDPR, UK GDPR, CCPA/CPRA and India's DPDP; when you self-host, you are the data controller. SOC 2 and ISO 27001 assess the organisation that runs a service, so they apply to you, not to the project. What AdLedger gives that organisation is controls and evidence that make those audits easier.
| Framework | What AdLedger provides | Guide |
|---|---|---|
| GDPR / UK GDPR | Consent modes, export, erasure, retention, hashing, masking, audit trail | Art. by Art. |
| CCPA / CPRA | Global Privacy Control, consent-aware uploads, access and delete | Requirements |
| ePrivacy / PECR | Consent-required and cookieless pixel modes, banner snippets | Cookies |
| SOC 2 | Controls that map to CC6 (access), CC7 (monitoring), CC8 (change), C1 and P criteria | Mapping |
| ISO/IEC 27001:2022 | Supports the relevant Annex A controls | Mapping |
| OWASP Top 10, ASVS, CIS Docker | Self-assessed against the public lists; no formal verification | Tables |
Not covered: HIPAA and health data, and children's data. Card data never touches AdLedger (your payment provider holds it). See what is not covered and the go-live checklist.
| Area | Controls |
|---|---|
| Sign-in | Free two-factor sign-in (TOTP + recovery codes) that owners can require org-wide, with a documented break-glass for a locked-out owner. scrypt passwords under a NIST SP 800-63B-4 policy. |
| Sessions | Hashed tokens, idle timeout and maximum lifetime, a device list with sign out one or everywhere, new-device emails. |
| Access | Five built-in roles plus custom roles with per-page and per-action permissions. Contact emails masked by role, with every reveal audited. Separate permissions for aggregate CSVs, contact exports and PDFs. |
| PII | Raw emails only in the contacts table; SHA-256 hashes everywhere else. IPs truncated. Stored payloads redacted. |
| Secrets and keys | Connector credentials and 2FA secrets encrypted with AES-256-GCM. API keys stored hashed, with scopes and optional expiry. |
| Audit | Tamper-evident, hash-chained audit log with Verify, filters and CSV export. Security alerts for new keys, webhooks, role changes, 2FA resets, bulk exports and new-device sign-ins. |
| Consent | Pixel consent modes (opt-out, consent required, cookieless) and Global Privacy Control. Conversion uploads carry consent signals, and people who said no are never uploaded. |
| Data rights | Per-contact export and erasure (UI and API), full workspace export, raw-event retention. |
| Leak deterrence | Watermarked, fingerprinted PDFs verifiable at /verify, an export log, aggregate-only share links. |
| Web and supply chain | CSP and security headers, SSRF guards, signed webhooks. CodeQL, dependency review, pnpm audit, Trivy image scans, Dependabot, SBOM and provenance on release images. |
| Disclosure | /.well-known/security.txt on every install and private vulnerability reporting (SECURITY.md). |
Read the Trust and security page for the mechanisms and the hardening checklist, and the Compliance guide for the framework mappings and the statements that are safe to make about your install.
One Next.js app and PostgreSQL. The dashboard, REST API, pixel collector, webhooks, MCP server, live stream, PDF rendering and background jobs all run in a single container.
your website ──al.js──▶ /api/v1/collect ─────┐
forms, CRMs ──webhook─▶ /api/v1/webhooks ────┤
Stripe, stores ─webhook▶ /api/v1/webhooks ───┼──▶ AdLedger (Next.js) ──▶ PostgreSQL 16
ad platforms ◀── scheduled sync / uploads ───┤ ▲ dashboard, /share, /verify
Claude, Cursor ──MCP──▶ /api/mcp ────────────┘ └──▶ signed webhooks out
Stack: Next.js 16 · React 19 · TypeScript · PostgreSQL 16 (Drizzle ORM, embedded PGlite for trials) · Tailwind CSS v4 + shadcn/ui · Recharts · react-pdf · Vercel AI SDK · MCP SDK · vitest · Playwright. Details and design decisions: docs/ARCHITECTURE.md.
| Doc | What's in it |
|---|---|
| Features | Every page and setting, grouped |
| Self-hosting | Install options, HTTPS, upgrades, backups, configuration |
| Connectors | Setting up each integration, UTM templates, mock mode |
| Site-builder guides | Webflow, Wix, Squarespace, Framer, Next.js, GTM, Shopify, WordPress |
| Pixel | The tracking script, its API and consent |
| Reports | PDF reports, AI documents, schedules, watermarks and verification |
| API · Webhooks · MCP | REST API, signed outbound webhooks and recipes, AI assistant tools |
| Trust and security | Controls, privacy, hardening checklist, disclosure |
| Compliance | GDPR, CCPA, SOC 2, ISO 27001, OWASP and CIS mappings, go-live checklist, safe claims |
| FAQ | Data, accuracy, iOS, cost, 2FA lockout, compliance questions |
| Architecture · Product · Roadmap | How it's built, who it's for, what's next |
What is shipped and what is next lives in docs/ROADMAP.md. Ideas and votes are welcome in issues.
pnpm install
pnpm dev # http://localhost:3000, embedded database, no Docker needed
pnpm test # vitest on an embedded Postgres, every connector mocked
pnpm lint && pnpm typecheck
pnpm build && pnpm e2e # Playwright browser tests with axe accessibility checks
Bug reports, connectors, report kinds and docs fixes are welcome. Start with CONTRIBUTING.md and the roadmap. Found a security issue? See SECURITY.md.
AdLedger is source available under the Functional Source License, FSL-1.1-ALv2, a "Fair Source" licence. It is not an OSI-approved open source licence.
Contributions are accepted under the same licence (see CONTRIBUTING.md). The name and logo
are covered by TRADEMARKS.md. The WordPress plugin in integrations/wordpress is a separate
work licensed GPL-2.0-or-later, as WordPress.org requires.
Built by Shubham Vankalas, as a free-to-self-host tool for founders who want to know which ad paid off.
If AdLedger shows you which ad made you money, give it a star. It helps other founders find it.
Website · Issues · Contribute
TypeScript
93.6%
HTML
2.3%
CSS
1.8%
JavaScript
1.5%
Self-hosted ad attribution, revenue ledger and CRM. See which ad actually made you money. Free to self-host, source available (FSL-1.1).
See the code
See which ad actually made you money, what that customer really cost, and prove it.
Self-hosted ad attribution, revenue ledger and CRM.
Free to self-host. Source available (FSL-1.1). Your server, your data.
AdLedger joins ad spend (Meta, Google and 7 more networks), website events from a 2.4 KB pixel, leads and real payments (Stripe and 12 more) into one ledger, so every number is computed in SQL, split to the cent and shown per campaign, ad set and ad. One container plus PostgreSQL, on a server you control.
Not sure yet? Take the 3D product tour, or run the demo below with 90 days of sample data.
Free to self-host, with the source on GitHub. No per-seat or revenue-share pricing. Unlimited users, workspaces and client logins.
Your data never leaves your server. No telemetry, no licence check, no phone-home.
You need Docker. This starts AdLedger with 90 days of demo data:
git clone https://github.com/ShubhamVankalas/adledger.git && cd adledger
ADMIN_EMAIL=admin@example.com ADMIN_PASSWORD=adledger-demo-123 DEMO_DATA=true docker compose up -d
Open http://localhost:3000 and sign in. The demo runs on mock connectors that speak each platform's
real API format (Meta, Google, TikTok, LinkedIn, Microsoft, Stripe). Or run plain docker compose up -d,
create your account and choose Explore with demo data.
$env:ADMIN_EMAIL="admin@example.com"; $env:ADMIN_PASSWORD="adledger-demo-123"; $env:DEMO_DATA="true"
docker compose up -d
Point an A record at the server, open ports 80 and 443, then:
curl -fsSL https://raw.githubusercontent.com/ShubhamVankalas/adledger/main/install.sh | DOMAIN=ads.yourcompany.com sh
The script installs nothing but AdLedger: it downloads docker-compose.yml, writes a .env with
generated secrets, and starts the app, PostgreSQL 16 and Caddy. Re-run it to upgrade.
| Where | How |
|---|---|
| Render | render.yaml: web service, managed PostgreSQL 16 and a generated APP_SECRET. |
| Railway | Deploy from your fork (uses the Dockerfile and railway.json), add PostgreSQL, set DATABASE_URL=${{Postgres.DATABASE_URL}}. |
| Coolify, Dokploy, CapRover, Portainer | Deploy docker-compose.yml as-is. |
| Single container, no PostgreSQL | docker run -d -p 3000:3000 -v adledger:/data ghcr.io/shubhamvankalas/adledger (embedded database; fine for trials, use PostgreSQL for production). |
pnpm install && pnpm dev # http://localhost:3000, embedded database in ./.data
Upgrade with docker compose pull && docker compose up -d. Backups, HTTPS and every setting:
docs/SELF_HOSTING.md.
![]() |
The Overview is a widget board. Press Customize (or
|
|
Visitors on your site right now, today vs the same time yesterday, and a real-time feed of ad clicks, visits, leads, payments and refunds (server-sent events, no extra service).
| ![]() |
![]() |
Campaigns, ad sets and ads with column presets, NC-ROAS, a platform gap column (what the platform reports next to what AdLedger verified), a quadrant that sorts campaigns into scale, test, fix and kill, and saved views with a peek into the people a campaign brought in. |
|
First touch, last touch and linear, switchable anywhere, with exact integer-cent splits that always add up to the payment. Paths shows the journeys customers took, Time to convert shows whether your attribution window is long enough, and unattributed revenue is always shown, never hidden. | ![]() |
![]() |
Customers: LTV and cohorts. Lifetime value by acquiring channel, LTV:CAC and a cohort heatmap by first-payment month (retention, cumulative LTV or revenue), with a dot where each cohort paid back its CAC. Renewals are credited to the journey that first acquired the customer. |
|
Ad Receipts. Every payment shows which ads earned it, what that customer cost in ad spend and when they paid it back. Customer costs plus unallocated equal total spend, to the cent.
|
Profit Ledger. Enter cost of goods, payment fees and shipping once. Get contribution, profit after ads, POAS, break-even ROAS and a P&L waterfall, plus which ads bring buyers who refund.
|
|
Truth Gap. "Meta says its ads made you this much; real payments from people who clicked them were that much." Claimed vs verified conversions and value per platform and campaign. |
Too-early guardrails. Median and p80 days from first click to first payment, a "too early to judge" tag on young campaigns, and pause drafts you download as a Meta or Google Ads Editor file. AdLedger never writes to your ad accounts. |
![]() Contacts. Saved views, filters, groups, bulk actions with undo, fast at 10k+ contacts. | ![]() Record page. Ad clicks, visits, forms and payments on one timeline, plus notes, tasks and attribution. | ![]() Pipeline. Drag by mouse, touch or keyboard. Payments move contacts to Won automatically. |
Also: My tasks, CSV import with a preview before anything is written, and duplicate review and merge with re-attribution.
![]() |
Eleven print-ready PDF reports: executive summary, weekly performance, attribution model comparison, LTV and cohorts, wasted spend, channel mix, lead source quality, creative and ad leaderboard, funnel and time to convert, pipeline and CRM activity and profit and refunds. Your logo on the masthead, a methodology appendix, a "Prepared for" watermark and a fingerprint on every
page that anyone can check at |
AI document generator. Pick one of 12 prompt templates (monthly client report, board update, post-mortem, budget memo, Meta vs Google, lead quality audit, stand-up, case study, creative brief, quarter review, funnel leaks, refunds) or write your own. Your model writes the words; AdLedger draws every KPI, table and chart from SQL, removes any sentence with a number that is not in the data, and lays it out as a branded, fingerprinted PDF with an in-app preview.
|
Action cards (move budget, room to grow, revenue drop, CAC up) where every figure links to its source row, a weekly report marked All numbers verified, and Ask: plain-language questions answered from read-only SQL tools, with the table each answer came from. Any number a model invents is flagged. Works with no model at all, a local model (Ollama, LM Studio) or OpenAI, Anthropic, Gemini, OpenRouter, DeepSeek and any OpenAI-compatible endpoint. | ![]() |
G then a letter jumps between pages; ? lists shortcuts.
A dedicated Developers area (owners and admins by default) for wiring AdLedger into your own tools:
reports:read, mcp, contacts:read, contacts:pii, ingest:write), optional expiry, stored hashed.lead.created, contact.created, contact.updated, payment.succeeded
and payment.refunded: HMAC-SHA256 signatures, retries with backoff for about two days, a 30-day delivery
log with redeliver, Send test event, masked emails unless you opt in, private URLs blocked.
docs/WEBHOOKS.md# Pull leads with a read key
curl -H "Authorization: Bearer al_..." https://your-adledger/api/v1/leads
Ask Claude, Cursor or any MCP client "which ads made money last month?" against your own ledger. Create a key in Developers → API keys, then:
claude mcp add --transport http adledger https://your-adledger/api/mcp --header "Authorization: Bearer al_..."
get_overview, get_performance, find_wasted_spend, compare_periods, get_platform_breakdown,
get_timeseries, search_campaigns, contact_stage_funnel, list_contacts, get_contact_journey,
get_ad_receipt, get_latest_insights, get_sync_status, list_integrations.
Every tool is annotated read-only and a test proves none of them changes data. Emails are masked. Setup for Claude Desktop and Cursor: docs/MCP.md.
Connected from Settings → Integrations, with step-by-step instructions on each card and a mock mode for every connector.
| Ad platforms | Meta Ads, Google Ads, Microsoft Ads, TikTok Ads, LinkedIn Ads, Pinterest Ads, Snapchat Ads, Reddit Ads, X Ads. Anything else by CSV or the Spend API. |
| Payments and stores | Stripe (paste one key, the webhook is created for you), Shopify, WooCommerce, Paddle, Lemon Squeezy, Razorpay, PayPal, Chargebee, Recurly, Gumroad, Cashfree, Instamojo, PhonePe. Anything else by CSV or the Conversions API. |
| CRMs | Won deals from HubSpot and Pipedrive. |
| Lead forms | Any form with data-adledger-lead, Typeform, Tally, Webflow, Zapier or Make webhooks, native Meta Lead Ads, Google Ads lead forms, TikTok Lead Generation and WhatsApp click-to-chat. |
| Your website | One <script> tag (2.4 KB gzipped), a WordPress/WooCommerce plugin, a Shopify custom pixel, a GTM template and guides for Webflow, Wix, Squarespace, Framer and Next.js. |
| Back to the ad platforms (beta) | Consent-aware conversion upload to the Meta Conversions API and Google Ads, hashed identifiers only. |
| Notifications | Email, Slack, Discord, Microsoft Teams, SMS (Twilio), signed webhook. |
Connectors other than Meta, Google Ads and Stripe are in beta: tested against real-format fixtures, not yet verified on live accounts. Details: docs/CONNECTORS.md.
| Overview | Revenue and ROAS by attribution model |
|---|---|
![]() | ![]() |
| Time to convert | Time to money and pause drafts |
![]() | ![]() |
| Ask your numbers | Security policy and posture checklist |
![]() | ![]() |
| 30+ integrations | Guided setup checklist |
![]() | ![]() |
| Tracking snippet and consent modes | Members and roles |
|---|---|
![]() | |
| Alert rules and anomaly detection | Hash-chained audit log |
![]() | ![]() |
| Two-factor sign-in and devices | Notification channels |
![]() | ![]() |
| Verify a PDF report | |
![]() |
On your phone: installable as an app, with a floating tab bar and a one-tap filter sheet.
AdLedger is self-hosted software, so it holds no certification and makes no compliance claim on your behalf. It ships GDPR-ready tooling and SOC 2-aligned controls to help you meet GDPR, UK GDPR, CCPA/CPRA and India's DPDP; when you self-host, you are the data controller. SOC 2 and ISO 27001 assess the organisation that runs a service, so they apply to you, not to the project. What AdLedger gives that organisation is controls and evidence that make those audits easier.
| Framework | What AdLedger provides | Guide |
|---|---|---|
| GDPR / UK GDPR | Consent modes, export, erasure, retention, hashing, masking, audit trail | Art. by Art. |
| CCPA / CPRA | Global Privacy Control, consent-aware uploads, access and delete | Requirements |
| ePrivacy / PECR | Consent-required and cookieless pixel modes, banner snippets | Cookies |
| SOC 2 | Controls that map to CC6 (access), CC7 (monitoring), CC8 (change), C1 and P criteria | Mapping |
| ISO/IEC 27001:2022 | Supports the relevant Annex A controls | Mapping |
| OWASP Top 10, ASVS, CIS Docker | Self-assessed against the public lists; no formal verification | Tables |
Not covered: HIPAA and health data, and children's data. Card data never touches AdLedger (your payment provider holds it). See what is not covered and the go-live checklist.
| Area | Controls |
|---|---|
| Sign-in | Free two-factor sign-in (TOTP + recovery codes) that owners can require org-wide, with a documented break-glass for a locked-out owner. scrypt passwords under a NIST SP 800-63B-4 policy. |
| Sessions | Hashed tokens, idle timeout and maximum lifetime, a device list with sign out one or everywhere, new-device emails. |
| Access | Five built-in roles plus custom roles with per-page and per-action permissions. Contact emails masked by role, with every reveal audited. Separate permissions for aggregate CSVs, contact exports and PDFs. |
| PII | Raw emails only in the contacts table; SHA-256 hashes everywhere else. IPs truncated. Stored payloads redacted. |
| Secrets and keys | Connector credentials and 2FA secrets encrypted with AES-256-GCM. API keys stored hashed, with scopes and optional expiry. |
| Audit | Tamper-evident, hash-chained audit log with Verify, filters and CSV export. Security alerts for new keys, webhooks, role changes, 2FA resets, bulk exports and new-device sign-ins. |
| Consent | Pixel consent modes (opt-out, consent required, cookieless) and Global Privacy Control. Conversion uploads carry consent signals, and people who said no are never uploaded. |
| Data rights | Per-contact export and erasure (UI and API), full workspace export, raw-event retention. |
| Leak deterrence | Watermarked, fingerprinted PDFs verifiable at /verify, an export log, aggregate-only share links. |
| Web and supply chain | CSP and security headers, SSRF guards, signed webhooks. CodeQL, dependency review, pnpm audit, Trivy image scans, Dependabot, SBOM and provenance on release images. |
| Disclosure | /.well-known/security.txt on every install and private vulnerability reporting (SECURITY.md). |
Read the Trust and security page for the mechanisms and the hardening checklist, and the Compliance guide for the framework mappings and the statements that are safe to make about your install.
One Next.js app and PostgreSQL. The dashboard, REST API, pixel collector, webhooks, MCP server, live stream, PDF rendering and background jobs all run in a single container.
your website ──al.js──▶ /api/v1/collect ─────┐
forms, CRMs ──webhook─▶ /api/v1/webhooks ────┤
Stripe, stores ─webhook▶ /api/v1/webhooks ───┼──▶ AdLedger (Next.js) ──▶ PostgreSQL 16
ad platforms ◀── scheduled sync / uploads ───┤ ▲ dashboard, /share, /verify
Claude, Cursor ──MCP──▶ /api/mcp ────────────┘ └──▶ signed webhooks out
Stack: Next.js 16 · React 19 · TypeScript · PostgreSQL 16 (Drizzle ORM, embedded PGlite for trials) · Tailwind CSS v4 + shadcn/ui · Recharts · react-pdf · Vercel AI SDK · MCP SDK · vitest · Playwright. Details and design decisions: docs/ARCHITECTURE.md.
| Doc | What's in it |
|---|---|
| Features | Every page and setting, grouped |
| Self-hosting | Install options, HTTPS, upgrades, backups, configuration |
| Connectors | Setting up each integration, UTM templates, mock mode |
| Site-builder guides | Webflow, Wix, Squarespace, Framer, Next.js, GTM, Shopify, WordPress |
| Pixel | The tracking script, its API and consent |
| Reports | PDF reports, AI documents, schedules, watermarks and verification |
| API · Webhooks · MCP | REST API, signed outbound webhooks and recipes, AI assistant tools |
| Trust and security | Controls, privacy, hardening checklist, disclosure |
| Compliance | GDPR, CCPA, SOC 2, ISO 27001, OWASP and CIS mappings, go-live checklist, safe claims |
| FAQ | Data, accuracy, iOS, cost, 2FA lockout, compliance questions |
| Architecture · Product · Roadmap | How it's built, who it's for, what's next |
What is shipped and what is next lives in docs/ROADMAP.md. Ideas and votes are welcome in issues.
pnpm install
pnpm dev # http://localhost:3000, embedded database, no Docker needed
pnpm test # vitest on an embedded Postgres, every connector mocked
pnpm lint && pnpm typecheck
pnpm build && pnpm e2e # Playwright browser tests with axe accessibility checks
Bug reports, connectors, report kinds and docs fixes are welcome. Start with CONTRIBUTING.md and the roadmap. Found a security issue? See SECURITY.md.
AdLedger is source available under the Functional Source License, FSL-1.1-ALv2, a "Fair Source" licence. It is not an OSI-approved open source licence.
Contributions are accepted under the same licence (see CONTRIBUTING.md). The name and logo
are covered by TRADEMARKS.md. The WordPress plugin in integrations/wordpress is a separate
work licensed GPL-2.0-or-later, as WordPress.org requires.
Built by Shubham Vankalas, as a free-to-self-host tool for founders who want to know which ad paid off.
If AdLedger shows you which ad made you money, give it a star. It helps other founders find it.
Website · Issues · Contribute
TypeScript
93.6%
HTML
2.3%
CSS
1.8%
JavaScript
1.5%