Version 1.3.0
ConvertDash documentation
Everything you need to measure people, not machines: one tag to install, a
dashboard to read, and the rules behind every number. Search the ConvertDash documentation with
/ from anywhere on the page.
Quick start Install on your platform The dashboard AI visibility Count crawlers Settings Read API Self hosting Plans
Contents
Start here
Quick start
Four steps, and most people are done in five minutes. Nothing to install on your site beyond one script tag.
- Sign up. Create an account at analytics.convertnow.tools. The first seven days include everything a paid single site gets, plus All sites. No card.
- Add your site. Open Sites and tags, press Add site, and enter the domain and a name. You get a site key and a finished tag.
- Paste the tag. Put it inside the
<head>of every page. Installing on your platform shows where that is on WordPress, Shopify, Webflow and the rest. - Press Test from my browser. It opens your site, sends one visit from your own browser, and tells you whether it got through and why. If it did not, press Check installation. It reads your page and names the problem: a missing tag, a caching plugin, a Content Security Policy or the wrong domain.
Your tag looks like this, with your own key in place of YOUR_SITE_KEY:
<script defer data-no-optimize="1" data-no-defer="1" data-cfasync="false" nowprocket
src="https://analytics.convertnow.tools/cd.js?k=YOUR_SITE_KEY&v=1.0.2"></script>
Why the extra attributes. They tell LiteSpeed Cache, WP Rocket, SiteGround Optimizer and Cloudflare Rocket Loader to leave the tag alone. Without them those tools often hold scripts back until the visitor scrolls, and some visits are never counted. Keep them, even if your site does not use any of these.
The ?k= part matters. It is how the server knows which site a visit
belongs to, and it is how your dashboard settings reach the tag without you editing
any HTML.
Once visits arrive, open Explore for the whole site on one board, or any report from the menu. Reading your dashboard walks through them.
Prefer to run it on your own server? Self hosting takes about ten minutes with Docker.
Installing on your platform
Every platform ends up doing the same thing: one script tag in the head of every page. No plugin is needed anywhere. Pick yours and copy the code:
WordPress
Without a plugin. Paste the tag into your theme’s header, just
before </head>, or into the header box of any code snippet plugin
you already use. The tag reads WordPress body classes, so posts, pages, archives,
search results and 404s are all recognised with nothing extra.
With the optional plugin. A free WordPress plugin can paste the tag for you. It does nothing the tag cannot do on its own, so use it only if you prefer not to touch theme files.
Signed in editors are skipped automatically: when the WordPress toolbar is on the page, the visit is not counted. Change that in Settings.
WooCommerce
Install the tag as for WordPress. Orders are then read from the order received page by themselves, with the amount and currency. Each order counts once, even if the buyer reloads the page.
Shopify
Online Store, Themes, Edit code, then layout/theme.liquid. Paste the
tag just before </head>. To count orders, add the same tag to the
order status page too, under Settings, Checkout. The tag then reads each finished
order.
Menu names move. Hosted builders rename their settings from time to time. If a label below does not match, look for Custom code, Code injection or Head code in the site settings.
Webflow
Site settings, Custom code, Head code. Paste the tag and publish.
Wix
Settings, Custom code, Add custom code. Paste the tag, choose all pages, and place it in the head.
Squarespace
Settings, Advanced, Code injection. Paste the tag into the header box.
Ghost
Settings, Code injection, Site header. Ghost prints author structured data on posts, so the Editorial reports fill in without any extra work.
Next.js, React and other single page apps
Add the tag to the head of your root layout or index.html. Route
changes are followed automatically, so each new page in the app counts as a view.
If your router changes the view without changing the address, call
convertdash.pageview() yourself when a new view appears. Doing both
counts the same view twice, so turn automatic tracking off with
data-spa="0" when you do this.
Google Tag Manager
Create a Custom HTML tag with the code from the Tag Manager tab above, set it to fire on all pages, and use the Initialization trigger so it starts as early as possible. A direct tag in the head is still the better choice when you can add one.
Plain HTML
Paste the tag inside <head> on every page, or in the shared
layout your pages use.
What the tag picks up by itself
No plugin and no extra code. The tag reads what your pages already say.
| Authors | From the author meta tag, the article’s structured data, or a byline link marked as the author. Feeds the Editorial reports. |
| Page types | Posts, pages, products, archives, search results and the home page, from WordPress body classes, structured data or Open Graph. |
| Missing pages | A WordPress 404, or a page whose title says it was not found. These land in Broken Links. |
| Site search | Anything searched with ?s=, ?q=, ?query= or ?search=. Only the term is kept. |
| Shop orders | The WooCommerce order received page, and the Shopify order status page when the tag is on it. Each order is counted once. |
| Route changes | In single page apps, each new route counts as a view. |
| Your own visits | On WordPress, anyone with the admin toolbar showing is skipped. |
When a page does not say these things itself, set them on the tag with
data-type, data-author and data-author-name.
See Tag options.
Search terms that do not look typed are dropped. The same parameter names often carry reset keys, signed links or email addresses. So email addresses, web addresses and long random strings are thrown away rather than recorded. Losing the odd real search is the cheaper mistake.
Tag options
All optional. Most sites never need any of them, because your dashboard settings
reach the tag through its ?k= key. Add an attribute to change one page
without changing the setting for the whole site.
| Attribute | Example | What it does |
|---|---|---|
data-type | product | What kind of page this is. 404 marks a not found page. |
data-author | Jane Doe | Who wrote the page, as a name or a numeric id. |
data-author-name | Jane Doe | The name to show when data-author is an id. |
data-events | 1 | 1 captures outbound, download, email and phone clicks on this page. 0 turns click capture off. |
data-files | pdf,zip | File extensions that count as downloads. |
data-selector | .cta | Extra elements to count clicks on. The label comes from data-cd-label on the element, or its text. |
data-dwell | 2000 | Milliseconds on screen before a view counts without any interaction. The default is 2000. |
data-mode | i | i counts only views with a real interaction. |
data-spa | 0 | 0 stops following route changes in single page apps. On by default. |
data-search | 0 | 0 stops recording site search terms on this page. |
data-search-keys | s,q,term | Which address parameters count as a search. |
data-frames | 1 | Count pages shown inside a frame. Off by default, so an embedded page does not add a second view. |
data-api | https://…/collect | Send visits to a different collector address. |
data-site | YOUR_SITE_KEY | The site key, for a tag loaded from an address without ?k=. |
data-dnt | 1 | 1 skips readers who send Do Not Track or Global Privacy Control on this page. The site setting decides by default. |
data-purchase | 1 | 1 exposes window.convertdash.purchase() on this page. Same as the Purchase call setting. |
Custom events
Clicks on outbound links, downloads, email links and phone links are captured on their own once you switch them on under Settings, Clicks and events. For anything else, send an event yourself after the tag has loaded:
convertdash.event('signup', { plan: 'pro' });
convertdash.event('video_play', 'homepage');
The first argument is the event name. The second is optional: a short text value, or an object whose first value is kept. Only one value is stored, on purpose, so an events table never turns into a log of personal data by accident.
Events appear in the Events section. Use them as goals in Behavior to see how often a visit ends in that action.
Revenue
Every sale is tied back to the visit that brought it: channel, landing page, referrer, campaign, author and AI assistant. Pick the method that fits your checkout. Each order is counted once, however many times it arrives.
WooCommerce and Shopify
Nothing to set up. The tag reads the order from the thank you page. On Shopify, add the tag to the order status page too, under Settings, Checkout.
Any thank you page
Put this element on the page buyers see after paying, filled in by your platform:
<div data-cd-order="ORDER-123" data-cd-amount="1499.00" data-cd-currency="INR" hidden></div>
A redirect
If your checkout can send buyers to a thank you address of your choice, add the order to it:
https://example.com/thanks?cd_order=ORDER-123&cd_amount=1499.00&cd_currency=INR
JavaScript
For a checkout that finishes without loading a new page:
convertdash.purchase({ id: 'ORDER-123', amount: 1499.00, currency: 'INR' });
From your server
For Stripe, Paddle, Gumroad, Lemon Squeezy, a Zapier webhook or your own backend. The server token is in Settings, Advanced.
curl -X POST https://analytics.convertnow.tools/api/sites/SITE_ID/orders \
-H "Authorization: Bearer SERVER_TOKEN" \
-d order_ref=ORDER-123 -d amount=1499.00 -d currency=INR
A refund is the same call with -d event=refund, and it is subtracted
so the net figure matches your shop. Send your payment provider’s own order id and
webhook retries do no harm. Orders sent from a server have no visit attached, so they
count in totals and show as (not attributed) in the channel and page breakdowns.
Optional fields make the figures match your shop exactly: tax and
shipping give the excluding tax and shipping figure, renewal=1
marks a subscription renewal (counted in revenue, not in conversions), and
status says whether it was paid. Only paid orders are counted. Cancelled
one later? Send -d event=status -d status=cancelled and it leaves the
figures. Orders in a currency other than your reporting currency are shown beside the
total, never added to it.
Set your reporting currency under Settings, Revenue. Until the first order arrives, the Revenue screens show how to send one.
Machines
Counting machines that never run JavaScript
The tag runs in browsers. Most crawlers never run it, so on its own the tag only sees the machines that execute scripts: headless browsers, some AI agents, link previewers that render. GPTBot, ClaudeBot, Googlebot and the SEO crawlers fetch the HTML and leave. To count them, your server tells ConvertDash what it saw. People are still counted by the tag only, so nothing here can change your visitor numbers.
What is stored. A date, a kind, a name, a path and a count. The address of the machine is used once to check that a crawler is who it says it is, then discarded. The full user agent is never stored.
Option 1: send requests from your server
Post a batch of up to 500 requests to your site’s machines endpoint. Authenticate with the
server token from Settings, Advanced. Some shared hosts strip the Authorization
header, so X-CD-Token works too.
POST https://analytics.convertnow.tools/api/sites/SITE_ID/machines
X-CD-Token: YOUR_SERVER_TOKEN
Content-Type: application/json
{
"batch_id": "web1-2026-09-22T10:05",
"items": [
{ "ua": "Mozilla/5.0 (compatible; GPTBot/1.2)", "path": "/pricing", "ts": 1790071500, "ip": "20.171.207.2" },
{ "ua": "Mozilla/5.0 (compatible; Googlebot/2.1)", "path": "/blog", "ts": 1790071502 }
]
}
| Field | What it is |
|---|---|
ua | The user agent string. Required. Plain browsers are ignored. |
path | The path that was requested. Query strings are dropped. |
ts | Unix seconds. Optional, defaults to now. Older than 48 hours is skipped. |
ip | Optional. Used only to verify a claimed crawler, then discarded. |
method, status | Optional. Only GET and HEAD are counted. |
batch_id | Optional. A retried batch with the same id is not counted twice for 24 hours. |
The answer says how many were received, counted as machines, ignored as people, and verified. Keep sends to at most two a second per site. Filter on your side first: only forward requests whose user agent is not a plain browser, and nothing is added to a normal page load.
Option 2: import your access logs
Self hosted installs only. The log importer runs as a command on the server ConvertDash is installed on, so on the hosted service Option 1 above is how server side hits arrive. It covers the same ground: your server posts what it saw, and only named machines are counted. On your own server:
php bin/convertdash logs:import --site=1 --file=/home/USER/logs/access.log
php bin/convertdash logs:import --site=1 --file='/var/log/nginx/access.log*' # rotated and .gz files too
Combined and common log formats, LiteSpeed logs and Cloudflare Logpush JSON lines are detected on their own. Run it hourly from cron and each run picks up where the last one stopped.
Real crawler or impostor
Anyone can put Googlebot in a user agent. When an address comes with the request, ConvertDash checks it against the ranges the operator publishes, or with a forward confirmed reverse DNS lookup for operators that verify that way. A claim that fails is filed as Fake followed by the name, so impersonation shows up in Filtered Traffic instead of hiding inside it. Without an address the name is taken at its word.
The dashboard
Reading your dashboard
The left menu holds every report, grouped by the question it answers, with Explore at the top. Every screen follows the date range, the comparison and any filter you set, and every chart can be downloaded as a picture.
Explore
One board for the whole site. Pick a goal, split everything by a segment (channel, device, browser, country, source, campaign, landing page, new or returning, assistant or not), and compare with the previous period or between two saved segments. The cards:
- Key numbers with a sparkline and the change against the comparison.
- Live now: visitors in the last 5 and 30 minutes, with their pages and sources, refreshed every 30 seconds.
- Traffic by channel over time, stacked so the layers add up to all visits.
- Source and campaign attribution: visitors, visits, bounce rate, conversion rate, revenue and revenue per visit, sortable.
- Top pages with entries, exit rate and share of converting visits.
- Funnel split by device or browser, goal completions, top events, retention, where visits go, and devices, browsers and countries with their conversion rates.
- Insight explorer: choose a metric, a breakdown, a chart and a granularity, then save the card to the board.
Drag cards to reorder them, hide the ones you do not need, and download any card as CSV. The board is saved per person and per site.
One counting rule everywhere. A visit belongs to the channel, source, campaign, device and landing page of its first pageview. Conversion rate is visits that completed the goal divided by visits.
The report sections
| Section | What it answers |
|---|---|
| Editorial | Which authors and content types bring readers in |
| Pages | Which pages are read, where visits start and end, and page flow for any page |
| AI Visibility | Assistants that send people, crawlers that read pages, and how the two relate |
| Filtered Traffic | Every bot, crawler and scanner that was refused, by name |
| Referrers | Which sites and channels send visitors |
| Campaigns | UTM source, medium and campaign |
| Geographic | A world map, countries, continents and languages |
| Devices | Device types, browsers, systems and screens |
| Behavior | Goals, funnels, journeys, retention, engagement, segments and cohorts |
| Audience | New and returning visitors, and how they engage |
| Revenue | Orders and what brought them |
| Events | Clicks, downloads, missing pages and site search |
| Growth | How traffic changes, and a calendar of every day |
| Data | AI insights and exports |
Every section opens with an at a glance screen: tiles, a trend, and short ranked lists. Long tables are paginated and searchable.
Behavior, drawn
| Screen | What you see |
|---|---|
| Journeys | A flow diagram of the first 2 to 6 steps of every visit, with where people left at each step. Hover a page to light its whole path. Start from or end at any page. |
| Funnels | Each step with the part that continued and the part that dropped, step and overall rates, the median time between steps, where the dropped went next, and the same funnel split by device, channel, country or browser. |
| Goals | Conversion rate over time per goal, rate by source, and how long a visit took to convert. |
| Retention | A cohort grid of visitors seen again after their first week or day, with the average curve above it. |
| Engagement | Pages placed by views and engaged time, sized by entries and coloured by exit rate, plus how far readers of a page get through it. |
| Page flow | For one page: where its visits came from, and where they went next. |
| Segments and cohorts | Groups of visits side by side against the whole site. |
Retention needs a longer visitor window. With the default one day window nobody can be recognised on a later day, so the retention grid explains that and links to the setting instead of drawing an empty chart.
Filters, dates, comparison and notes
Add a filter, such as one country, one campaign or one author, and it applies to every report until you remove it. Pick a preset range or custom dates, switch on compare to see the previous period beside each number, and add a note to the chart to mark a launch. The main chart can also draw a trend line, a smoothed average, unusual days and a forecast; choose which under Settings, Display.
Export
Download CSV, TSV, JSON or NDJSON by visits, pageviews, events or daily totals. The export uses the filters on screen.
AI
AI visibility and AI insights
Two different machines read your site for AI. A crawler (GPTBot, ClaudeBot, PerplexityBot, Bytespider and others) reads pages to train or index. An assistant fetch (ChatGPT-User, Perplexity-User, Claude-User) reads a page because a person asked a question just then. Separately, an assistant can send a person to you: that is a visit, counted like any other, with the assistant as its source. ConvertDash keeps the three apart.
Which assistants are recognised
Visits are matched to an assistant by the referring host, and by utm_source
when the assistant strips the referrer, as ChatGPT often does. The list covers ChatGPT,
Perplexity, Claude, Gemini, Copilot, Grok, DeepSeek, Meta AI, Le Chat, NotebookLM, Kagi,
You.com, Phind, Poe, Duck.ai, Kimi, Qwen, Doubao, HuggingChat, T3 Chat and Monica. An
assistant that sends neither a referrer nor a tag shows as direct, and nothing can change
that from your side.
The AI Visibility screens
| Screen | What it shows |
|---|---|
| AI Overview | Share of voice by assistant, week by week. Assistant referrals indexed against your site’s own growth. How those readers engage and convert compared with search and with everyone, with a significance test so small differences are called small. Revenue from assistant visits. |
| Crawl to referral | Per page: how often crawlers read it, how often assistants fetched it for someone, and how many people assistants sent to it. Pages read a lot and never cited are listed on their own, and so are pages cited but never seen crawled. |
| Crawler analytics | Crawls per bot over time, the median days between crawls of a page, which sections take the crawl budget, and bots seen for the first time. A helper drafts a robots.txt block per bot and an llms.txt starter from your top pages, and a button checks your live robots.txt and llms.txt. |
| Assistants, AI pages, AI machines | The original ranked lists: visits by assistant, pages they land on, machines by name, and pages machines read. |
Crawler numbers need server side data. Most crawlers never run the tag. Send requests or import logs as described in Counting machines, or the crawler screens only show the few that render pages.
AI insights
Under Data, AI insights is a feed of findings, ranked, each with the number, a small chart, a confidence, the reasoning and a next step. The models run on your server every night and the screen opens instantly. Nothing is sent anywhere.
| Group | How it is worked out |
|---|---|
| What changed | Level shifts found with a changepoint search over the daily series, and period changes broken down by channel, source, page, country and device to show what drove them. |
| What is unusual | The expected day comes from a seasonal decomposition with the weekly pattern. A day is unusual when it sits far from that, tested so that pure noise almost never raises an alert. |
| What is coming | A forecast for the next weeks with a range. It is only shown when it beat a simple same weekday last week baseline in a backtest, and the backtest error is stated. |
| Who converts | Which traits of a visit go with completing your goal, with confidence ranges, shown only when the model is good enough to trust. Visit personas from clustering. Channel credit from a Markov chain. |
| AI traffic | Growth of assistant referrals against the site, what they are worth, and pages models read but do not cite. |
| Suspicious traffic | Counted sources whose visits look automated even though they passed the filters. Listed for you to judge, never removed. |
Pin a finding to keep it at the top, dismiss one you have dealt with, or press Rebuild now. Findings need some history: most groups wait for about four weeks of data and enough visits to say anything with confidence.
Written summary, optional. With your own API key in
CD_AI_PROVIDER and CD_AI_KEY, a short written summary of the
findings appears on top. Only headlines and numbers are sent, never rows or visitors, and
Preview shows exactly what would be sent. Without a key, nothing leaves the server.
What counts as a visit
A pageview is counted when the page actually painted on screen and then either the visitor did something (moved, tapped, typed, scrolled) or it stayed in front of them for two seconds. Time only runs while the tab is visible, so a background tab nobody looked at never counts.
Both halves matter. Paint alone would count prerenders and forgotten tabs. Interaction alone would count scripts that click.
Every pageview also carries a small proof of work that the browser solves in a few milliseconds. A script that posts straight to the endpoint without running the tag has no proof, so it is refused and tallied under Filtered Traffic as unverified. Tags cached from before the update get a week of grace.
Where a visit came from
A visit belongs to the source, channel and campaign of its first pageview. A reader who arrives from Google and then clicks three internal links is one Google visit with four views, not one Google view and three direct ones. Visits end after 30 minutes of silence or at midnight in the site’s timezone, whichever comes first.
Why the numbers differ from Google Analytics
- Bots are filtered. Crawlers, AI crawlers, scanners, headless browsers and data centre traffic are refused and listed in Filtered Traffic.
- Visitors are counted per day. The identifier rotates daily by default, so someone who visits on Monday and again on Tuesday counts as two visitors in a weekly total. You can choose a longer window in Settings.
- Unseen pages do not count. Prerenders, prefetches and tabs opened in the background are left out.
- Privacy signals are honoured. Browsers sending Do Not Track or Global Privacy Control are skipped by default.
- Your own visits are skipped. On WordPress, signed in editors are not counted.
iCloud Private Relay visitors are always counted, because the server keeps Apple’s published list of relay addresses and never treats them as a data centre. VPN visitors who interact with the page are counted like anyone else.
Filtered traffic
Everything the collector refuses is counted by kind and by name, so your visitor number can be checked rather than taken on faith. The Filtered Traffic section shows:
| AI crawlers | GPTBot, ClaudeBot, CCBot and others reading the web in bulk |
| AI assistant fetches | An assistant reading a page because a person asked it something |
| Search engines | Googlebot, Bingbot and friends |
| SEO tools | Ahrefs, Semrush and similar |
| Link previews | Slack, WhatsApp or LinkedIn unfurling a link |
| Scripts and headless browsers | curl, scrapers and automated browsers |
| Scanners | Machines probing for weaknesses |
| Data centre traffic | Browsers on cloud and hosting addresses that never interact |
Refused traffic is stored as counters, never as a log: a date, a name, a page and a number. None of it is added to your visitors.
Under Settings, Tracking you can choose the bot filter level. Standard is the default. Strict also drops anything that is not a recognisable browser. Off counts everything, and is only for debugging.
Settings
Settings reference
Every setting, its default, what it changes and when a change takes effect. Settings are per site and live under Settings in the dashboard.
Visits already stored keep what they have. A setting that changes what is stored, such as country or the returning visitor window, applies to new pageviews.
Tracking
| Setting | Default | What it does | Applies |
|---|---|---|---|
| Site name | the domain | Shown in the site picker and at the top of the weekly summary. | At once |
| Domain | Beacons are accepted from this domain and its subdomains. Changed under Sites and tags. | At once | |
| Collect data | on | Off refuses every beacon for the site. Data already stored is kept. | At once |
Accuracy and privacy
| Setting | Default | What it does | Applies |
|---|---|---|---|
| Bot filtering | standard | Standard refuses named crawlers and tools, requests with the wrong headers, and pageviews with no proof of a person. Strict also refuses browsers whose environment reports oddly and any agent that is not a recognisable browser. Off counts everything that reaches the endpoint, proof included. Refused requests are tallied under Filtered Traffic. | At once |
| Count a view after | 2000 | How long a page has to stay in front of somebody, in milliseconds, before it counts without them touching anything. 1000, 2000, 3000, 5000 or 10000. Time runs only while the tab is in front. | Next pageview |
| What proves a person | either | Either: an interaction or the dwell above. Interaction: only a pointer, tap, key, wheel or scroll counts, staying never does. The server refuses a dwell only view under the interaction rule even from a stale tag. | Next pageview |
| Data centre addresses | on | Refuses pageviews from cloud and hosting ranges that show no interaction. A cloud address that scrolled or tapped is counted, because VPNs exit there. iCloud Private Relay addresses are never treated as data centre traffic. Strict bot filtering refuses them all. Tallied as datacenter. | At once |
| Filtered traffic | on | Keeps counters of what was refused: a date, a kind, a name, a path, a number. Off, refusals are still refused but not counted, and the Filtered Traffic screens are empty. | At once |
| Keep filtered counters for | 180 | Days the refusal counters are kept. 0 keeps them. | Hourly housekeeping |
| Do Not Track | on | A browser sending DNT: 1 or Sec-GPC: 1 is not recorded. The refusal is tallied as excluded so the gap is visible. Brave sends GPC on every request. | At once |
| Your own visits | off | On a WordPress site the tag sees the admin toolbar and skips the page. On, editors are counted. | Next pageview |
| Country data | on | Looks the country up from the address on the server and stores the two letter code. Off, nothing is stored and the Location screens stay empty from then on. | New pageviews |
| Recognise a returning visitor for | 1 | Days the visitor identifier stays the same: 1, 30, 90, 365, or 0 for never rotated. One day means nobody can be followed past midnight. Longer windows turn on returning visitors and cross day retention and must be disclosed. | New pageviews |
| Flood protection | on | Caps one address at 300 accepted requests a minute and one visitor at 30. Past the cap, requests are refused and tallied as flood. | At once |
| Visit gap | 30 | Minutes of silence that end a visit. A pageview within the gap, on the same local day, joins the previous visit. Set through the settings API. | At once |
Revenue
| Setting | Default | What it does | Applies |
|---|---|---|---|
| Record orders | on | Off, orders from the tag, the thank you page and the API are refused. One row per shop and order reference, so a resent order never counts twice. | At once |
| Purchase call | off | Exposes window.convertdash.purchase() in the tag. | Next pageview |
| Revenue reports | on | Shows or hides the Revenue section in the menu. | Next dashboard load |
| Currency | EUR | The currency revenue is reported in. Stored amounts are not converted. | At once |
Exclusions
| Setting | Default | What it does | Applies |
|---|---|---|---|
| Ignore IP addresses | empty | One per line. Exact addresses, wildcards such as 198.51.100.*, or CIDR ranges, IPv4 or IPv6. Matched on the server. Tallied as excluded. | At once |
| Ignore paths | empty | One per line, * as a wildcard. Matched against the stored path after the query string is removed. A pageview or click on a matching path is dropped without a trace. | At once |
| Query strings | on | Drops the query string from stored paths. Campaign tags and ad click ids are read into their own columns first and are never stored in a path either way. Off keeps every other parameter. | New pageviews |
| Except these parameters | empty | Parameter names, one per line, kept in the path when stripping is on, in a fixed order so two spellings of the same address are one page. | New pageviews |
Clicks and events
| Setting | Default | What it does | Applies |
|---|---|---|---|
| Outbound links | on | A click on a link to another domain. | Next pageview, and the server refuses the kind at once |
| File downloads | on | A click on a link whose extension is in the list. | Same |
| Counted as a download | pdf, doc, docx, xls, xlsx, ppt, pptx, zip, rar, 7z, csv, mp3, mp4, dmg, exe, pkg | The extensions. | Next pageview |
| Email links | on | mailto: links. | Same as outbound |
| Phone links | on | tel: links. | Same as outbound |
| Specific elements | off, empty | Clicks on anything matching a CSS selector, labelled with the element’s data-cd-label or its text. A matching element is filed here and not also as another kind. | Next pageview |
| Record 404s | on | A page whose title or WordPress body class says it is missing is stored as a notfound view and listed under Broken Links. Off, the view is refused and tallied as excluded. | At once |
| Record site searches | on | The search term read off the address. Values that look like a token, a link or an email address are never recorded. | Same as outbound |
| Search parameters | s, q, query, search | Which query parameters carry a search term. | Next pageview |
| Keep events for | 0 | Days clicks and events are kept. 0 follows the raw pageview window. | Hourly housekeeping |
Display
| Setting | Default | What it does | Applies |
|---|---|---|---|
| Default date range | 7d | What the dashboard opens on, and what an unknown range key falls back to. | Next dashboard load |
| Timezone | UTC | Where a day starts and ends in every report and the summary email. Changing it queues a rebuild of the daily summaries; the worker does it in batches and until then those days are read from raw rows, already in the new zone. Days whose raw rows have been pruned keep the summaries they have. | At once |
| Week starts on | Monday | Used by This week and the weekly charts. | Next report |
| Chart layers | off | Optional lines on the main chart, computed in the browser. | Next dashboard load |
Your data
| Setting | Default | What it does | Applies |
|---|---|---|---|
| Keep raw rows for | 365 | Days pageviews are kept. 0 keeps them. Filters, journeys, goals, funnels, cohorts and retention read raw rows and cannot see past this. | Hourly housekeeping, batches of 5000 |
| Keep daily summaries for | 0 | Days the summaries are kept. 0 keeps them. | Hourly housekeeping |
| Run housekeeping now | Applies the windows above at once. | ||
| Rebuild summaries | Queues a rebuild. The marker moves back so reports read raw rows meanwhile; the worker summarises forward, 90 days a run. The card shows progress. | Worker | |
| Delete all analytics data | Type the domain to confirm. Everything measured up to that moment is deleted in batches; a small site is emptied at once, a large one by the worker over its next runs. Views arriving after the click are kept. Settings, the tag, notes and people stay. | At once, then worker |
Weekly summary email
| Setting | Default | What it does | Applies |
|---|---|---|---|
| Send it | off | Next email | |
| How often | weekly | daily, weekly or every 30 days. | Next email |
| On | Monday | The weekday a weekly email goes, in the site’s timezone. Sent by the first worker run of that day and covering the seven finished days before it. Today is never included. | Next email |
| To | empty | Up to ten addresses. Empty sends nothing. | Next email |
Shared dashboard
| Setting | Default | What it does | Applies |
|---|---|---|---|
| Enable | off | Master switch. Off, an existing link shows nothing until it is turned back on. | At once |
| Password | none | Asked of anyone opening the link. At least six characters, hashed, cannot be shown again. Set when generating a link. | The next link generated |
| Expires after | 0 | Days until the link stops working. 0 means until withdrawn. | The next link generated |
Advanced
| Setting | Default | What it does | Applies |
|---|---|---|---|
| Extra allowed domains | empty | Other domains the same tag runs on. Beacons from anywhere else are refused and tallied as origin. Links from these domains to the site count as internal, not as referrals. | At once |
| Local development | off | Accept beacons from localhost and 127.0.0.1 for this site’s key. A debug install (CD_DEBUG) accepts them regardless. | At once |
| Route changes | on | Count client side route changes as pageviews, once the reader has interacted with the page. | Next pageview |
| Endpoint | collect | Install wide. The name of the collect endpoint, for when a blocklist learns the default. Set through the settings API; the tag picks the new name up on its own. | Next pageview |
Team
Invite colleagues or clients to your sites, each with their own sign in. Choose a role per site:
| Viewer | Can see reports |
| Editor | Can also change settings |
| Admin | Can also manage people |
People you invite do not use your site count, and they see your sites with your plan’s reports. Team is part of Agency.
All sites
Every site you can open, on one screen: totals across all of them, a trend for each, and a comparison table you can sort by any column. It is the quickest way to spot which site needs attention.
All sites comes with Pro Power and Agency, and with the free trial.
White label
Put your own brand, or your client’s, on the shared dashboard and the weekly email for a site. Under Settings, White label, set:
- Brand name, shown in the header.
- Logo, as the https address of an image. It is also used as the page icon.
- Accent colour, used for charts, links and buttons.
- Brand link, optional, for the name in the header.
- Hide the ConvertDash credit on the shared dashboard and in the email.
White label is part of Agency.
Sharing
Shared links
A shared link opens one site’s dashboard, read only, without signing in. Create one in Settings, Shared dashboard. You can protect it with a password of at least six characters and give it an expiry in days. The password is stored as a hash and cannot be shown again.
- Switching sharing off stops every link for the site at once. Switching it back on brings them back.
- Generate a new link to retire the old one.
- Wrong passwords are limited, so a link cannot be guessed open.
- On Agency, the link carries your white label brand.
Shared links come with every paid plan.
Read API
Read your reports as JSON. Create a token on your Account page and send it with every request. A token sees the same sites you do and cannot change anything. The Read API is part of Agency.
Authorization: Bearer cdk_your_token
Endpoints
GET /api/v1/sites | The sites you can see: id, name, domain, timezone. |
GET /api/v1/sites/{id}/summary | Visitors, visits, views and the rest of the overview, with the change against the period before and a daily series. |
GET /api/v1/sites/{id}/reports | Every report id and name, and whether the plan covering the site opens it. |
GET /api/v1/sites/{id}/reports/{view} | One report. Table reports take page and per (10 to 200 rows). |
GET /api/v1/sites/{id}/realtime | Visitors active in the last 5 minutes. |
Every call takes range: today, yesterday,
7d, 30d, 90d, 12mo or
all. Or send from and to as dates, like
from=2026-09-01&to=2026-09-10. The default is the last 30 days.
curl -H "Authorization: Bearer cdk_your_token" \
"https://analytics.convertnow.tools/api/v1/sites/1/summary?range=30d"
Sending data from your server
Two write endpoints take the site’s server token from Settings, Advanced, as a Bearer header or as X-CD-Token: POST /api/sites/{id}/orders for orders a browser never sees (see Revenue) and POST /api/sites/{id}/machines for crawler requests (see Counting machines). The server token is not a Read API token and cannot read reports.
Errors
401 | The token is missing or revoked. |
402 | The plan has lapsed. Requests answer 402 until it is renewed. |
404 | No such site, or you cannot see it. |
429 | Too many requests. Each token may make 600 requests every 10 minutes. |
Errors come back as {"error": "..."}.
Privacy
Privacy and what is stored
ConvertDash is built so the analytics do not need a consent banner in most places. Check your own rules; this is what the software does.
| Question | Answer |
|---|---|
| Cookies | None. The tag sets no cookie and reads none. |
| Browser storage | No localStorage. A session id sits in sessionStorage, which the browser deletes when the tab closes. |
| Visitor identifier | A one way hash of the address, the browser and a secret salt that rotates. By default it rotates every day, so today’s visitor cannot be matched to yesterday’s. You can choose 30, 90 or 365 days, or never, in Settings. |
| IP address | Used for the hash, the country lookup and the data centre check, then discarded. Never written to the database. |
| User agent | Reduced to browser, version, system and device type. The full string is never stored. |
| Query strings | Removed from stored paths by default. Campaign tags are read into their own columns first. |
| Do Not Track and Global Privacy Control | Honoured by default. The skipped view is tallied as excluded so the gap is visible. |
| Third parties | None. The tag, the lookups and the dashboard are all served by the install. Nothing is sent anywhere unless you turn on a check in or the written summary. |
| Refused traffic | Counted, never logged: a date, a kind, a name, a path and a number. |
What a self hosted install sends us
Two check ins, both described field by field in docs/licensing.md, which ships
with the install. The licence check in, once a week while a key is active, sends the key, a random install id, the domains you
track, how many sites, the versions of ConvertDash, PHP and the database, and a rough
pageview band. The product check in, which is asked for at install and off until you say
yes, sends the same facts without a key and with the monthly pageview count. No row of your
analytics, no path, no referrer and no visitor is in either. php bin/convertdash
checkin off stops the product check in and deletes what was sent.
Troubleshooting
Start with the two buttons on Sites and tags. Check installation reads your page and names the problem. Test from my browser sends one visit from your own browser and shows whether it got through, and if not, why.
No tag found
The tag is not in the page the dashboard fetched. Check that it is inside
<head> and on the live site, not only in a draft or a staging copy.
If you just added it, clear your site’s cache, because the old page may still be
served.
Caching and optimisation plugins
LiteSpeed Cache, WP Rocket, SiteGround Optimizer and Cloudflare Rocket Loader can
delay or combine scripts. The attributes on the tag ask them not to. If one still
delays it, add cd.js to that plugin’s list of scripts to leave alone
(in LiteSpeed Cache: Page Optimization, JS Delayed Includes Excludes; in WP Rocket:
File Optimization, Excluded JavaScript Files). Then clear the cache.
Cloudflare
If your site sits behind Cloudflare, the tag is not affected: it carries data-cfasync="false" so Rocket Loader leaves it alone, and each visit is a POST that no cache stores. Pages served from Cloudflare’s cache still run the tag in every browser, so every visit is counted. If numbers look low and nothing in Filtered Traffic explains it, check that Bot Fight Mode is not challenging requests to the analytics host.
Ad blockers and Brave
Some blockers stop analytics requests, and those visits cannot be counted. Brave also sends Global Privacy Control with every request, which ConvertDash honours by default. To test your own install, use a regular Chrome or Safari window.
Do Not Track
Browsers sending Do Not Track or Global Privacy Control are skipped by default. If your own test visit does not appear, this is often why. You can switch it off in Settings.
VPN
iCloud Private Relay visitors are always counted. VPN visitors who interact are counted too. A VPN visitor who never touches the page can look like data centre traffic and be refused. If many of your readers use a VPN, switch off the data centre filter in Settings.
Wrong domain
Visits from a domain the site is not registered under are refused. If your site also answers on another domain, add it under Settings, Advanced, Extra allowed domains.
Content Security Policy
If your site sends a Content Security Policy, it must allow the tag to load and to
send visits. Add the analytics address to script-src and
connect-src:
script-src 'self' https://analytics.convertnow.tools;
connect-src 'self' https://analytics.convertnow.tools;
My numbers are lower than another tool
Expected. See What counts as a visit, then open Filtered Traffic: the difference is listed there by name.
Your own server
Self hosting
ConvertDash runs on your own server as well as ours. It is the same code, the same tag and the same 60+ reports. The code is public at github.com/prateekzare/convertdash. The key you buy for Pro Single, Pro Power or Agency works here as well as on the hosted service. Or buy the Lifetime licence with one payment. Self hosted has no pageview limit, on any plan.
One key, both ways. A yearly key works on analytics.convertnow.tools and on your own servers, even at the same time: it counts hosted accounts and servers separately. A Lifetime key works on your own servers only. An install without a key runs the free rules on your own data: one site and the core reports, with no pageview limit and no history limit. It never stops collecting.
Requirements
| You need | Details |
|---|---|
| Docker | Docker Engine with the Compose plugin. The easiest way, and it brings its own database. |
| Or PHP and a database | PHP 8.1 or newer with pdo_mysql, openssl and mbstring. MySQL 8 or MariaDB 10.6 or newer. No Composer packages. |
| Memory | 1 GB is enough for most sites. Give the database more as traffic grows. |
| An address with HTTPS | Your sites load the tag from it, and browsers block it over plain HTTP. A subdomain such as analytics.example.com is usual. |
| Cron | Only without Docker. Two lines, shown below. |
Docker quick start
git clone https://github.com/prateekzare/convertdash.git
cd convertdash
cp .env.example .envSet two things in .env:
CD_DB_PASS=something long and random
CD_PUBLIC_URL=https://analytics.example.comCD_PUBLIC_URL is the address a browser uses to reach this install. It goes into
every tag, so if it is wrong the tag points nowhere. Then start it:
docker compose up -dThe first start takes about forty seconds while the database sets itself up. Open your
address (or http://localhost:8080 on your own machine), fill in one form, and you
have an account, a site and a tag. Four containers run: web (nginx),
app (PHP), worker (rollups, retention and the licence check in) and
db, which has no published port.
Prefer a ready image to building one? Each release is published as
ghcr.io/prateekzare/convertdash with its version as the tag.
Without Docker: a VPS or shared hosting
Upload the code (the release zip from GitHub, or git clone), create an empty
database, and fill in CD_DB_* and CD_PUBLIC_URL in
.env. Then, over SSH:
cp .env.example .env
php bin/convertdash install [email protected] --password='a long password' --domain=example.com
php bin/convertdash doctorPoint the domain’s document root at the public/ folder. Nothing above it may be
reachable from the web. On Apache and LiteSpeed the shipped public/.htaccess
already has the rules. On nginx:
server {
server_name analytics.example.com;
root /srv/convertdash/public;
location / { try_files $uri /index.php$is_args$args; }
location ~ ^/index\.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root/index.php;
}
location ~ \.php$ { return 404; }
}Add two cron lines. On shared hosting (Hostinger, cPanel and similar) they go in the panel’s cron screen, with the full path to your folder:
*/5 * * * * php /srv/convertdash/bin/convertdash worker >/dev/null 2>&1
* * * * * php /srv/convertdash/bin/convertdash tick >/dev/null 2>&1The first runs rollups, retention, digests and the licence check in. The second writes waiting pageviews to the database within a minute on a quiet site. Shared hosting needs no Redis and no Docker: pageviews are queued in a file on disk.
Reverse proxy and HTTPS
ConvertDash speaks plain HTTP and expects something in front of it to handle HTTPS. Caddy is the shortest way, and fetches the certificate by itself:
analytics.example.com {
reverse_proxy localhost:8080
}With nginx in front, pass the address along:
location / {
proxy_pass http://127.0.0.1:8080;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}Then tell ConvertDash which proxies to believe, or anybody could fake their address past the rate limits:
CD_TRUSTED_PROXIES=127.0.0.1
# behind Cloudflare, its published ranges are expanded for you:
# CD_TRUSTED_PROXIES=cloudflare,127.0.0.1Do not add a cache rule for the analytics address in Cloudflare or any CDN. ConvertDash
marks every dynamic answer no-store, and a cache that ignores that changes your
numbers.
Activating your licence
In the dashboard, open Settings, Licence. Paste the key and press Activate. The screen shows the plan, how many of its installs are in use, when the next check in is due, whether an update is available, and a Deactivate button. From the command line:
php bin/convertdash license activate --key=CD-XXXXX-XXXXX-XXXXX-XXXXX
php bin/convertdash license status
php bin/convertdash license check
php bin/convertdash license deactivateWith Docker, put docker compose exec app in front of each. One message you may
see:
- All servers are in use. A yearly key covers 1, 2 or 5 servers (Pro Single,
Pro Power, Agency) and Lifetime covers 2. Run
license deactivateon the server you no longer use, or release it from the email the lost key form on the product page sends you.
The install checks in once a week, and verifies the licence against a signature it already holds, so it keeps working when it cannot reach us. A Lifetime licence never expires. A yearly licence runs to the end of the year you paid for, and when it lapses without renewal the install moves to the free rules after a short grace period. A refunded key steps down the same way. Collection never stops and there is never a pageview limit.
Updating
Settings, Licence says when a newer version is out. With Docker:
git pull
docker compose build
docker compose up -dThe app applies database changes when it starts. Without Docker, replace the code but keep
.env and storage/, then run:
php bin/convertdash ingest:flush
php bin/convertdash migrate
php bin/convertdash doctorRelease notes are on GitHub releases. Take a backup first.
Backups
Everything that matters is in the database plus your .env file. With Docker:
docker compose exec -T db sh -c 'mysqldump -u"$MYSQL_USER" -p"$MYSQL_PASSWORD" "$MYSQL_DATABASE"' | gzip > convertdash-backup.sql.gzWithout Docker, mysqldump the database the usual way, or use your host’s
backup tool. Keep .env with the dump. CD_APP_KEY in it salts every
visitor hash, so restoring with a different key breaks visitor continuity at that point.
Moving to another server
- Run
php bin/convertdash license deactivateon the old server. That frees one of the two installs. - Copy the database dump and
.envto the new server. - Restore the dump and start ConvertDash there, as above.
- Run
php bin/convertdash license activate --key=...on the new server, and point your DNS at it.
Old server already gone? Use the lost key form on the product page. The email lists your installs and lets you release one. Or write to us and we release it.
Scaling up
One box with Docker handles a busy site. When you need more:
- Run several web containers behind a load balancer. Set
CD_SESSION_DRIVER=dbso a sign in works on every one of them, and share thestoragevolume between them. - Run as many worker containers as you like. Scheduled work takes a database lock first, so only one of them does each job.
/healthzand/readyzanswer load balancers and orchestrators. The Docker image reports its own health too.- The repository has a ready Compose file for this:
deploy/compose/docker-compose.scale.yml.
The scaling guide has the settings, a measured benchmark and a sizing guide. A Redis queue and Kubernetes manifests are on the list for later releases.
Uninstalling
Deactivate the licence first, so the install is free for somewhere else:
php bin/convertdash license deactivateWith Docker, docker compose down stops everything and keeps your data.
docker compose down -v also deletes the database volume, and that cannot be undone,
so take a backup first. Without Docker, remove the two cron lines, drop the database and
delete the folder. Then take the tag off your sites.
Plans and billing
Every new hosted account starts with a seven day free trial. It includes everything a paid single site gets, plus All sites. No card, nothing to cancel. After seven days the account moves to the free plan and keeps collecting. Prices are on the pricing section of the product page, in your currency.
| Free | Pro Single | Pro Power | Agency | Lifetime | |
|---|---|---|---|---|---|
| Runs on | Hosted, or your server without a key | Both, one key | Both, one key | Both, one key | Your server |
| Billing | Free | Yearly | Yearly | Yearly | Once |
| Sites | 1 | 1 | 5 | Unlimited | Unlimited |
| Pageviews a month, hosted | 10k | 100k | 1M | 5M | Not hosted |
| Pageviews, self hosted | No limit | No limit | No limit | No limit | No limit |
| Accounts on one key, hosted | No key | 1 | 2 | 5 | Not hosted |
| Servers on one key, self hosted | No key | 1 | 2 | 5 | 2 |
| History | 30 days hosted, full self hosted | Full | Full | Full | Full |
| Reports | Core | All 60+ | All 60+ | All 60+ | All 60+ |
| Events and revenue | No | Yes | Yes | Yes | Yes |
| Exports, shares, weekly email | No | Yes | Yes | Yes | Yes |
| All sites | No | No | Yes | Yes | Yes |
| Team, White label, Read API | No | No | No | Yes | Yes |
The core reports on the free plan are pages, referrers, campaigns, geographic, devices and filtered traffic. The trial has the Pro Single column plus All sites, with 100k pageviews.
Pageviews are a soft allowance, and only on the hosted service. Go over and nothing stops counting. We email you at 80 and 100 percent of the month’s allowance and suggest the next size. On your own server there is no pageview limit at all, with the same key.
When a trial or plan ends. History older than 30 days is hidden, not removed, and each locked report names the plan that opens it. The free plan keeps 90 days of detail, and a paid plan that lapses keeps its full history for 30 more days first. Buy a plan inside that window and all of it is visible again at once.
Accounts and servers
One yearly key works in as many hosted ConvertDash accounts as the plan allows (one for Pro Single, two for Pro Power, five for Agency), and on the same number of your own servers. The two are counted separately. Removing the key from an account or a server frees its place for another. Lifetime works on two of your servers, such as production and staging. See moving to another server.
Refunds
Fourteen days, no questions, on every plan including Lifetime: email us. A full refund retires the licence. A hosted account moves to the free plan; a self hosted install moves to the free rules. Nothing you collected is deleted either way. A partial refund is reviewed by a person before anything changes.
Upgrading
Open Subscription in your dashboard and pick a plan. The plan applies to your account the moment the payment clears. Confirm your email address first: the plan cards show before that, but the payment step does not. An upgraded key keeps working in both places, for the difference in price. A Lifetime licence already has everything, so there is nothing to upgrade.
Licence keys
Plans bought on the product page come as a licence key by email. For a hosted plan, paste it under Subscription, Licence key, and the plan applies straight away. Removing the key there takes the account back to free and frees the key for another account. It does not cancel a yearly renewal: do that from the Razorpay receipt in your email, or reply to it. Paid by card in another currency? Press Manage billing on the Subscription screen, or use Manage your card subscription on the product page. For a self hosted key, yearly or Lifetime, see activating your licence.
Already have a hosted key and need more sites? The upgrade form on the product page charges the difference between the two plans, once. Card subscriptions pay it on Stripe’s own checkout page and come straight back. Your key and renewal date stay the same.
Currencies and VAT. Prices are shown in US dollars unless your time zone or language points to another currency, and the list above the plans switches it. Nothing is stored in your browser to remember the choice. Rupees are charged through Razorpay or Cashfree, every other currency through Stripe, and you pay exactly the price shown. Where VAT applies it is already inside that price. A business in the EU outside Germany can enter its VAT number at checkout and is reverse charged.
Paying through Cashfree. Where the price list says Cashfree, you enter your email and phone number on the product page (Cashfree needs both), pay on Cashfree’s own page and come straight back to your key. Cashfree sells twelve months as one payment. Before it runs out we email you a link to renew for another year.
Lost your key? We store a hash rather than the key, so nobody can look it up. Enter your email in the recovery form on the product page. We email a link that works for one hour. Your old key keeps working until you open that link and confirm; only then is a fresh key issued and the old one retired.
Referral programme
Anyone can join, customer or not. You get a link and a code, and you earn 10% of what the people you send pay us.
- Join. Enter your name and email in the referral section of the product page. We email your link, your code and a private link to your earnings.
- Share. Your link looks like
https://convertnow.tools/convertdash/?ref=YOURCODE. A buyer can also type the code under “Have a referral code?” next to the plans. Signing up for the hosted service throughanalytics.convertnow.tools/signup?ref=YOURCODEkeeps the code on the account for when they buy. - Earn. 10% of every payment they make: the first purchase, renewals, upgrades and Lifetime, in the currency they paid in, without any tax the payment provider reports.
A commission is pending for 14 days, the refund window. Then it is approved, and paid once we send it, with an email each time. A refunded payment voids its commission. Your own purchases earn nothing. Buyers never see who referred them, and you never see their address.
The earnings link in your email lasts 30 days. To get a fresh one, use “Already joined?” in the same section.
The licence, in full
Written out because a licence you have to email somebody about is a licence nobody reads. Everything below is how the software behaves. The plan table it refers to is on the pricing section of the product page.
1. The first seven days
Every new hosted account gets the Pro Single column plus All sites for seven days. Team, White label and the Read API stay on Agency. No card is asked for and there is nothing to cancel. On the eighth day the account moves to the Free column and keeps collecting.
History older than 30 days is hidden rather than removed, and each locked report names the plan that opens it. The free plan keeps 90 days of detail, so pay within three months and the older data is visible again at once, including the weeks you spent on the free plan.
2. What a key attaches to: accounts and servers
A Pro Single, Pro Power or Agency key works in two places at once, and each is counted on its own.
On the hosted service it attaches to accounts on analytics.convertnow.tools. Buy inside the dashboard and the plan applies the moment the payment clears. Buy on the product page and you paste the key under Subscription once. The plan says how many accounts one key may sit in: one, two or five. Remove the key from an account and its place is free for another.
On your own servers it attaches to installs: your own servers, each identified by a random id it creates on first run. A yearly key allows one, two or five at once (Pro Single, Pro Power, Agency), and a Lifetime key two, usually production and staging. There is no pageview limit on any of them. An install is a server, not a site, so one install can track as many sites as you like. Moving? Run php bin/convertdash license deactivate on the old server first and the place frees at once. Old server already gone? Release it from the email the lost key form sends, or write to us.
A Lifetime key works on your own servers only. The hosted service refuses it with a message that says so.
3. Where the visitor data lives
Hosted: your readers’ requests reach our servers, and what the collector keeps is written there: a visitor identifier that rotates daily by default, the page, the referrer, the country, the device and similar facts. IP addresses are never stored. We show you your own reports and do nothing else with it: no selling, no ad networks, no data brokers, no profiles of your readers or of you. You can export it and you can ask us to delete it, and deletion means deletion.
Self hosted: it is written to your own database and stays there. None of it is sent to us.
4. The check in, and exactly what it sends (self hosted)
Two check ins exist. A licence check in happens when you activate a key and then once a week. A product check in, which the installer asks about and which is off until you say yes, happens once a month so we know how many installs exist and which versions to keep supporting.
What they send: the random install id, the address you configured, the domains you track, how many sites there are, the ConvertDash, PHP and database versions, the platform, and the number of pageviews recorded in the last thirty days. One number. The licence check in also sends your key, because that is what it is for.
What they never send: any row of traffic, any visitor, any page path, any referrer, any figure from any dashboard, any email address, any account.
php bin/convertdash checkin off stops the product check in and deletes the record of your install on our side. See the exact message with php bin/convertdash checkin preview, and read src/License/ in the source.
5. If our server is unreachable, nothing happens (self hosted)
Installs sit behind firewalls and on closed networks, where an outbound call fails for reasons nobody can fix from here. The entitlement is stored on your server and verified against a public key that ships with the install, so an install that cannot reach us keeps every feature it paid for. A Lifetime licence never expires. A yearly licence runs to the end of its year.
A yearly licence that lapses, or any licence that is refunded or revoked, steps down after a grace period. Collection continues at full speed, every row stays where it is, and the dashboard keeps working under the free rules, with no history limit on your own server.
6. Your data is never held hostage
If a plan expires, is refunded, or you stop paying, collection carries on and the dashboard keeps working. You lose the paid features in the table above and nothing else. There is no kill switch in this product.
Self hosted, the rows are in your database and stay there. Hosted, the free plan shows the last 30 days and older rows are hidden rather than deleted. Pay again and they are back the same minute.
7. How your key is stored, and how you get it back
Not in plain text. We keep a keyed hash of it plus the first eight and last four characters, so a database breach here does not hand anybody a working key for every customer. The honest trade: we cannot look your key up.
Recovery is two steps. Type the address you bought with, and that mailbox gets a list of its licences by hint, each with a link that lasts an hour and works once. The link opens a page with one button. Press it and a new key is issued, shown once and emailed. Only then does the old key stop. Nobody who merely knows your email address can take your key away.
8. What we are honest about
The code is public and readable. Anybody determined enough can remove the licence check, and no amount of cleverness would change that. So the licence is not a lock. It is a signed statement of what your install is entitled to, which cannot be forged without our private key, and it lets us count installs.
What carries the commercial weight lives on our side: the crawler signature feed a licensed install pulls, the updates, and hosted delivery. That is why there is no obfuscation in this product.
9. Renewals, cancelling and refunds
Yearly subscription: renews itself through Razorpay for rupee plans, and through Stripe for every other currency. A renewal moves the expiry to the end of the period it paid for, plus seven days of grace, so a card that declines and is retried does not drop you to free in between. Cancel any time by emailing us, or from the link in your renewal receipt, or for card plans from Manage billing. A licence paid until December runs until December.
One payment for 12 months (Razorpay when offered, and always at Cashfree): no auto renew, no surprise charge. We email before it lapses with a link to renew. If a yearly key lapses, a hosted account moves to the free plan and a self hosted install to the free rules, after the grace period. Both keep collecting and keep every row.
Lifetime (self hosted): one payment. It never renews and never expires, and every future update is included.
Refunds: fourteen days, no questions asked, on every plan. Email and it is done. A full refund revokes the licence and the account or install moves to free, with your collected data untouched. A partial refund changes nothing by itself: it is written on the licence and reviewed by a person, because a partial refund is usually a price adjustment, not a cancellation.
10. What you may and may not do
You may: run it on client sites, modify the source for your own use, and keep running the last version you had if you stop paying.
You may not: redistribute or resell ConvertDash itself, share a key across more accounts or installs than the licence covers, or offer it as a hosted analytics service to third parties without talking to us first. That last one is a conversation, not a no.