Which channel actually pays?
Revenue, orders and average order value per source and per platform. Returns from PayPal, Klarna & co. are recognised, so checkout redirects never steal the credit from the campaign that earned it.

Know which channels bring revenue, which pages convert and how your app compares to your website. Without cookies, without a consent banner, without storing a single IP address.
taci[ˈtaː.tʃi]Italian, imperative:be quiet.
POST /api/collect · text/plain · 173 bytes from 203.0.113.42 user-agent Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 …) { "d": "shop.example.com", "p": "/checkout/done", "tz": "Europe/Berlin", "l": "de-DE", "s": "newsletter", "n": "Purchase", "pr": { "value": "49.90", "currency": "EUR" } }
| visitor | 9c1f0be47d2a… today only |
|---|---|
| page | /checkout/done |
| country | DE from timezone |
| device | iOS · Safari · mobile |
| source | newsletter |
| goal | Purchase · €49.90 |
| ip | |
| cookie |
Revenue, orders and average order value per source and per platform. Returns from PayPal, Klarna & co. are recognised, so checkout redirects never steal the credit from the campaign that earned it.

UTM source, medium and campaign are picked up from every link. Known apps and referrers get readable names.

Any event becomes a goal. Click one and the whole dashboard narrows down to the visitors who converted.

Android, iOS and web in one view, with app versions and revenue per platform.

Countries from the browser's timezone, languages from the browser. No IP geolocation, no guesswork about people.

Cookie-based tools only see visitors who click “accept”. Tacilytics doesn't store or read anything on the device, so most sites can run it without a consent banner and see all of their traffic.*
* Whether you need consent depends on your setup and jurisdiction. Check with your data protection advisor; this is not legal advice.
No tag manager, no SDK maze, no third-party requests. Pick your stack:
<script defer data-domain="example.com"
src="https://analytics.example.com/tacilytics.js"></script>import Script from 'next/script';
export default function RootLayout({ children }) {
return (
<html lang="en">
<body>
{children}
<Script strategy="afterInteractive" data-domain="example.com"
src="https://analytics.example.com/tacilytics.js" />
</body>
</html>
);
}
// client-side route changes are tracked automatically<!-- once, in index.html -->
<script defer data-domain="example.com"
src="https://analytics.example.com/tacilytics.js"></script>
// anywhere in your components
window.tacilytics('Signup', { plan: 'pro' });<!-- once, in index.html -->
<script defer data-domain="example.com"
src="https://analytics.example.com/tacilytics.js"></script>
// in a component
window.tacilytics('Upgrade', { plan: 'team' });add_action('wp_head', function () {
echo '<script defer data-domain="example.com" '
. 'src="https://analytics.example.com/tacilytics.js"></script>';
});{% block layout_head_javascript_tracking %}
{{ parent() }}
<script defer data-domain="shop.example.com"
data-track-search="search"
src="https://analytics.example.com/tacilytics.js"></script>
{% endblock %}Tacilytics.init(
endpoint: 'https://analytics.example.com',
domain: 'example.com',
appVersion: '1.4.0',
);
MaterialApp(navigatorObservers: [TacilyticsRouteObserver()]);
Tacilytics.instance.purchase(value: 49.90, currency: 'EUR');curl -X POST https://analytics.example.com/api/collect \
-H 'Content-Type: application/json' \
-A 'MyApp/1.4 (ios)' \
-d '{"d":"example.com","p":"/product/42","pf":"ios",
"sid":"k3V9xQ2mP7aL0sZ4","av":"1.4.0"}'Everything in the dashboard, over a Bearer-key API with segmentation. The CLI speaks JSON, so scripts and AI agents read your numbers directly.
$ tacilytics stats shop.example.com 30d --json
{
"totals": { "visitors": 7464, "pageviews": 18528, "bounce": 26, ... },
"trend": { "visitors": 29, "pageviews": 28 },
"commerce": { "revenue": 21204, "orders": 273, "aov": 77.67, ... },
"sources": [{ "name": "Direct", "visitors": 6149 }, ...],
"goals": [{ "name": "Purchase", "visitors": 273, "cr": 3.7 }, ...]
}Not a setting, not a promise in a policy. It's how the counting is built.
Site, IP and user agent are combined with today's random salt and hashed. The IP itself is never written anywhere.
The salt lives in its own small file, mode 600, so it never ends up in a database dump or a backup of your data.
At midnight UTC the salt is overwritten. From then on those visits can't be linked to any later visit, not even by whoever runs the server. Limits
An event that arrives after its day has ended gets a one-off hash that can't be matched to anything.
The honest trade-off: a visitor who returns tomorrow is counted again. You lose cross-day journeys; you gain numbers you never have to apologise for.
Different goals, different trade-offs. Here is the honest version.
| Tacilytics | Google Analytics 4 | |
|---|---|---|
| Cookies on your visitors | None | Yes |
| Cookie banner needed for analytics | Usually not* | Yes, in the EU |
| IP addresses stored | Never | Processed by Google |
| Where your data lives | Your server, or ours in Germany | |
| Open source | Yes, MIT | No |
| Website and native apps in one dashboard | Yes | Yes |
| Follows one person across days and devices | No, by design | Yes |
| Advertising audiences | No | Yes |
* Depends on your whole setup and jurisdiction. Not legal advice.
One command on any server with Node.js. All features, no limits.
Read the docs CloudOn requestWe host and maintain your instance in Germany, with updates and daily backups.
Request a quote EnterpriseCustomDedicated infrastructure, data processing agreement, SLA, custom retention.
Contact salesFor each request the server hashes the site, the IP address, the user agent and a random salt that exists only for the current day. The IP is never stored. When the day ends the salt is overwritten, so that day's hashes can't be connected to any later visit. A visitor who returns tomorrow is counted again: reliable daily numbers, without following anyone.
Tacilytics doesn't store or read anything on the visitor's device, which is usually what triggers the consent requirement for analytics in the EU. Many teams therefore run it without a banner. Your exact obligations depend on your whole website and jurisdiction, so please confirm with your data protection advisor.
Some block analytics scripts by name or by known third-party domains. Because Tacilytics runs on your own domain and server, it is far less likely to be on those lists, but no tool can promise to be invisible to every blocker.
Node.js 18 or newer. Run npx tacilytics serve in an empty folder and put a TLS proxy such as Caddy or nginx in front. All data lives in one SQLite file in that folder.
Yes. There is a Flutter SDK, and any other stack can send a single JSON request. Apps appear in the same dashboard as your website, with a platform filter and revenue per platform.
Not at the moment. Tacilytics starts counting from the moment you add it. If an import matters to you, tell us.
Self-host in five minutes, or let us run it for your team.