Import from Umami
Run Pulse's published query against your Umami database and upload the result.
Read Import your history first for what an import is, who can run one, and how far back it can reach. This page covers Umami's export specifically.
Getting the export
Umami's own export button is not enough for an import: it downloads seven files of whole-range totals, with no dates in them, because Umami keeps no per-day export of its own. So instead, Pulse publishes a read-only query you run yourself, directly against your Umami database. It only reads; it never writes anything.
Replace the website ID in the query with your own (in Umami: Settings → Websites → Edit), then run it and save the result as a CSV file.
PostgreSQL (any self-hosted Umami version)
Save this as a file and run it with psql:
psql "$DATABASE_URL" -X -f pulse-umami-export.sql > umami-export.csv-- Pulse: Umami history export (PostgreSQL). Read-only.
-- Replace the website id below with your own (Umami: Settings, Websites, Edit),
-- then run: psql "$DATABASE_URL" -X -f pulse-umami-export.sql > umami-export.csv
COPY (
SELECT
to_char(we.created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS"Z"') AS created_at,
we.session_id::text AS session_id,
we.visit_id::text AS visit_id,
we.event_type AS event_type,
we.event_name AS event_name,
we.hostname AS hostname,
we.url_path AS url_path,
we.referrer_domain AS referrer_domain,
we.utm_source AS utm_source,
we.utm_medium AS utm_medium,
we.utm_campaign AS utm_campaign,
s.browser AS browser,
s.os AS os,
s.device AS device,
s.screen AS screen,
s.language AS language,
s.country AS country,
s.region AS region,
s.city AS city
FROM website_event we
JOIN session s ON s.session_id = we.session_id
WHERE we.website_id = '00000000-0000-0000-0000-000000000000'
-- Only if this website's tracking code runs on several hostnames and you
-- want one of them: uncomment the next line and put that hostname in it.
-- AND we.hostname = 'example.com'
ORDER BY we.created_at
) TO STDOUT WITH (FORMAT csv, HEADER true);MySQL or MariaDB (Umami v2 only; v3 runs on PostgreSQL alone)
Run both statements in one session, then export the result as CSV with its header row from your SQL client (phpMyAdmin, TablePlus, DBeaver, MySQL Workbench).
-- Pulse: Umami history export (MySQL or MariaDB, Umami v2). Read-only.
-- Replace the website id below with your own (Umami: Settings, Websites, Edit).
-- Run both statements in one session: the first makes created_at read back in UTC.
SET time_zone = '+00:00';
SELECT
DATE_FORMAT(we.created_at, '%Y-%m-%dT%H:%i:%sZ') AS created_at,
we.session_id AS session_id,
we.visit_id AS visit_id,
we.event_type AS event_type,
COALESCE(we.event_name, '') AS event_name,
COALESCE(we.hostname, '') AS hostname,
we.url_path AS url_path,
COALESCE(we.referrer_domain, '') AS referrer_domain,
COALESCE(we.utm_source, '') AS utm_source,
COALESCE(we.utm_medium, '') AS utm_medium,
COALESCE(we.utm_campaign, '') AS utm_campaign,
COALESCE(s.browser, '') AS browser,
COALESCE(s.os, '') AS os,
COALESCE(s.device, '') AS device,
COALESCE(s.screen, '') AS screen,
COALESCE(s.language, '') AS language,
COALESCE(s.country, '') AS country,
COALESCE(s.region, '') AS region,
COALESCE(s.city, '') AS city
FROM website_event we
JOIN session s ON s.session_id = we.session_id
WHERE we.website_id = '00000000-0000-0000-0000-000000000000'
-- Only if this website's tracking code runs on several hostnames and you
-- want one of them: uncomment the next line and put that hostname in it.
-- AND we.hostname = 'example.com'
ORDER BY we.created_at;Warning
Self-hosted on ClickHouse (Umami v3's alternative database)? This query is written for PostgreSQL and MySQL and returns nothing on ClickHouse. Pulse doesn't yet publish a ClickHouse version of the recipe.
Upload the CSV the query produced. If your website's tracking code runs on
more than one hostname and you only want one of them, uncomment the
hostname line in the query and fill it in before you run it: the filter
runs in your database, not in Pulse.
What's imported
Because this export carries one row per pageview rather than a day's totals, Umami's import can do a couple of things the other uploads can't:
- Visitors, visits and pageviews, per day
- Pages, and entry and exit pages, computed from the real rows rather than estimated
- Referrers and campaigns, including telling a homepage visit with no referrer apart from a shared link landing on some other page (see "Worth knowing" below)
- Countries, regions and cities
- Devices, browsers and operating systems
What isn't
- Custom events. The query selects them so a later release can read them without asking you to export again, but this release skips them.
- Bounce rate and visit duration. Pulse shows its own, measured from the days it tracked itself. See Why imported numbers differ.
Worth knowing
Umami's raw rows let Pulse tell Direct from a shared link. Most uploaded exports give Pulse only a day's totals, so a visit with no referrer always shows as Direct, whatever page it actually landed on. Umami's export carries the real landing page for every row, so Pulse can tell a homepage visit with no referrer (Direct) apart from someone landing on some other page with no referrer (Shared Link), the same distinction Pulse draws for traffic it measures itself.
Umami counts a unique visitor by rotating an anonymous identifier once a month. Pulse counts uniques by your site's own calendar month instead, so an imported month's visitor total is the sum of its daily counts, the same approach Pulse takes for Plausible's and Matomo's history too.
A tablet running Android can land in a different bucket than it would live. Pulse and Umami both read a device type from the browser's user agent, but they don't always agree on an Android tablet: it's a known, disclosed edge case that affects a small share of imported rows, not something an import can avoid.