Backup, export & moving Macs

Export as JSON or CSV, schedule a daily backup, import an export with per-item conflict resolution, and move Pulsaria to a new Mac.

Everything Pulsaria knows lives in plain files on your Mac, so a backup is a file you can hold. This page covers the two export formats, the scheduled daily backup, how an import merges into data that already exists, and the exact sequence for moving to another machine.

All of it sits in one place: the sidebar entry App Settings, cards Export data and Daily auto-export.

Manual export

The Export data card has three buttons: Export JSON, Export CSV and Import JSON. Both export buttons open a native Save dialog with the file name already filled in, and both keep working when your trial has expired — getting your data out is never blocked. Only Import JSON needs an active trial or a licence.

ButtonDefault file nameContains
Export JSONpulsaria-export-2026-07-25.jsonEverything, and the only file Import JSON reads back
Export CSVpulsaria-entries-2026-07-25.csvOne row per measurement, nothing else

The date in the name is your local calendar day. After saving you get a toast titled JSON export saved (or CSV export saved) with the path underneath, plus a line under the buttons reading Export saved: <path> for about four seconds.

What the JSON file contains

Pretty-printed JSON, 2-space indentation. The top level:

KeyWhat it holds
exportedAtISO timestamp of the moment you exported
versionAlways 1
projectsAll projects, complete
kpiDefinitionsAll KPI definitions, complete
entriesByDateObject keyed by YYYY-MM-DD, dates ascending — every entry of that day, sorted by createdAt ascending
alertsThe stored status alerts (at most 100)
fetchLogThe fetch log ring buffer (at most 500 records)
connectionsConnector connections as metadata: connector id, name, parameters and the Keychain referenceerence credentialRef

entriesByDate is the full history, not a rollup. If a KPI was written three times on one day, all three rows are in the file with their timestamps.

What the export deliberately leaves out

  • Connector credentials. API keys, tokens and Google Service Account JSON keys live in the macOS Keychain and never enter the file. The export carries only the reference name credentialRef, which is worthless without the Keychain entry behind it.
  • App settings. Theme, language, data directory, reminder settings, auto-export settings, dismissed hints and onboarding flags all live in config.json, which is not part of the payload.
  • Your licence. license.json is not exported. You enter the key again on the new machine.

There is also no way to export a subset — no date range, no single project, no single KPI. Every export is the complete dump.

One exception is worth knowing before you hand an export to anyone: a token you typed into a header row of a custom HTTP KPI is stored as plain text inside the KPI definition, not in the Keychain, so it is in the JSON file. See Custom HTTP sources.

The CSV file

The CSV is for spreadsheets, pivot tables and handing your numbers to something else. It contains only entries — no projects, no targets, no alerts, no connections, no fetch log.

kpiId,kpiName,projectName,date,value,createdAt
  • One row per stored entry. A KPI updated three times on one day produces three rows.
  • Rows are grouped by ascending date, and within a day by ascending createdAt.
  • KPI name and project name are resolved for you. A company-wide KPI has an empty projectName; an entry whose KPI has since been deleted keeps its kpiId but has an empty kpiName and projectName.
  • Values containing a comma, a quote or a line break are wrapped in double quotes, with inner quotes doubled.
  • The file starts with a UTF-8 BOM and uses CRLF line endings, so Excel gets umlauts right without an import wizard. There is no newline after the last row.

CSV is export-only. There is no CSV import.

Daily auto-export

The Daily auto-export card writes a dated backup once a day without you doing anything. Turn on the switch Automatic daily export; the remaining controls appear underneath it.

ControlDefaultNotes
Time18:00Local wall-clock time, HH:MM
FormatJSON + CSVAlternatives: JSON (full backup), CSV (spreadsheet / LLM)
Location<app data>/pulsaria/daily-exportRead-only field plus Choose…; a Reset button appears once you set a custom folder

The default folder is ~/Library/Application Support/com.onepixelahead.pulsaria/pulsaria/daily-export. Files are named exactly like the manual ones — pulsaria-export-<YYYY-MM-DD>.json and pulsaria-entries-<YYYY-MM-DD>.csv — and their contents are identical.

When it runs

The scheduler wakes up every 60 seconds while Pulsaria is open. It runs the export once per local calendar day, at or after the time you configured. If your Mac was asleep or the app was closed at 18:00, the run happens on the first tick after you open Pulsaria again that day — but it is not made up on a later day. Before writing, it refreshes your automatic KPIs so the snapshot is current; if that refresh fails, the backup is still written with the data that exists.

Two conditions apply: Pulsaria must be open — there is no background helper, see Schedules & refresh — and the scheduled run needs an active trial or a valid licence.

Status and running it by hand

At the bottom of the card sit a status line and the Export now button:

  • No export yet — never run.
  • Last export 2 hours ago — the last success, as a relative time.
  • Last export failed — check the location — hover it to read the actual error message.

Export now ignores the clock and the once-per-day rule and runs the same routine immediately, KPI refresh included. It reports the written file paths in a toast. Use it once after changing the location, to confirm the folder is really writable.

Location matters more than it looks. The card warns that other locations may only work while the app is open — the honest version is: a folder you selected through the card’s Choose… picker keeps its permission, because Pulsaria restores dialog-granted folders at launch. A path typed into a field never gets one, and the unattended run then fails against it. After changing the location, hit Export now once: if it writes the files, the scheduled run will too. If you want your backups somewhere Pulsaria never touches, the simplest pattern is to leave the default folder and let Time Machine or a sync client copy it.

Two more things to expect: a file for the same day is overwritten, and nothing is ever deleted. One JSON and one CSV per day accumulate indefinitely — prune them yourself if that matters. And there is no notification on failure; the status line in this card is the only signal.

Importing a JSON export

Import JSON reads a Pulsaria JSON export back in and merges it. It never wipes anything: new items are added, and for every item that already exists you decide individually.

The button is disabled without an active trial or licence, with the tooltip Requires a license or active trial.

Step 1 — what would be added

Pick a .json file. Pulsaria parses and analyses it without writing anything, then opens the Import dialog. Under Will be added you see one row each for KPIs, Connections, Entries, Projects and Alerts — but only the ones with a count above zero. If the file holds nothing new and only items that clash, that area reads Nothing new to add — only conflicts to resolve.

If there is neither anything new nor a conflict, no dialog opens at all. You get the toast Nothing new to import — everything in the file already exists.

When items clash, an amber note tells you how many, and the primary button becomes Resolve conflicts (n). Without conflicts it is simply Import.

Step 2 — one conflict at a time

An item conflicts when its internal id already exists locally. The dialog walks you through them, KPIs first, then connections, labelled Conflict 1 of 4. Each is shown as two columns:

ColumnFor a KPIFor a connection
Your versionName, Target (with unit), SourceName, Connector, Parameters
Imported versionthe same three fields, from the filethe same three fields, from the file

Three buttons:

  • Keep local — your version stays untouched.
  • Replace — the imported version overwrites yours.
  • Keep all remaining — everything still undecided stays local, and the import runs right away.

The import executes after the last decision. You then get Import complete with the per-type counts and, if anything was overwritten, a second toast: n existing item(s) replaced with the imported version.

How each kind of data is merged

DataMatched byBehaviour
ProjectsidNew ones are added. An existing project always keeps the local version — there is no keep/replace choice for projects.
KPIsidNew ones are added. Conflicts default to keep-local, overwritten only via Replace.
ConnectionsidSame policy as KPIs.
EntrieskpiId + createdAt, per dayAppend-only and deduplicated, so re-importing the same file adds nothing.
AlertsidNew ones merged in, sorted newest first, capped at 100.
Fetch logExported, but never imported. It is diagnostic data.

Two things are stripped on the way in, on purpose:

  • Every imported KPI loses its approval. A Bash or HTTP KPI that was approved on the old Mac arrives unapproved, and the scheduler skips it until you have looked at the actual command or URL and approved it again. That stops an export file from smuggling in a command that would run unattended. Connector KPIs never had an approval to begin with.
  • Every imported connection loses its verification state, so it reads as unverified until you re-enter the secret and test it.

Where import is strict, and where it is quiet

The file must be a JSON object with projects, kpiDefinitions and entriesByDate; anything else is rejected with Not a Pulsaria export (expected an object) or Not a Pulsaria export (missing projects / kpiDefinitions / entriesByDate). The version field is never checked.

Individual rows that fail validation are dropped without a word. A row is dropped when:

  • a KPI has no id or name, a target that is not a finite number greater than 0, no direction of up or down, or no source string,
  • a project’s status is not active, completed or on-hold,
  • an alert is missing any of id, kpiId, kpiName, newStatus, previousStatus, value, timestamp, dismissed,
  • a connection is missing id, name, connectorId, credentialRef, createdAt or parameters,
  • a date key in entriesByDate is not exactly YYYY-MM-DD.

Pulsaria counts those dropped rows but never shows the number. In practice this only bites hand-edited files — a KPI whose target you set to 0 vanishes from the import in silence. Check the counts in the Will be added list against what you expect before you confirm.

The write itself is staged. Projects, KPI definitions and connections go in as one block that is rolled back if any of the three fails. Alerts and entries are written afterwards, best-effort: a failure there leaves a consistent state but is not reported.

There is no undo for an import and no snapshot to roll back to. Run Export JSON first if you are importing into a Mac that already holds data you care about.

Reconnecting your connectors after an import

Because secrets never travel with an export, connector connections arrive as metadata only. Right after the import dialog closes, Pulsaria checks which of the connections it just wrote have no credential in this Mac’s Keychain, and opens the setup wizard for each of them in turn.

The header reads Reconnect Search Console with the sub-line Connection 1 of 3 — re-enter credentials, and an amber hint: “Credentials are never included in an export. Paste this connection’s key or token again to reactivate it on this machine.”

  1. The parameters — site URL, property id, region — are already filled in from the import. Check them, do not retype them.
  2. Paste the key or token. The “leave blank to keep the existing key” shortcut of normal editing is disabled here: a fresh secret is mandatory.
  3. Step through to Run test, then Save connection. Save stays disabled until the test comes back green.
  4. Closing the dialog skips that connection and immediately opens the next one.

Skipping is a one-way door. There is no reminder and no way to resume the walkthrough — you would fix it later under App Settings → Connections with the pencil icon. And a connection that never had a successful verification is drawn with a green check in the connection list rather than an amber warning, so a skipped one does not look broken until a fetch fails. See Connectors.

Connections whose connector this version does not know — an export from a newer version — are dropped from the queue without a message.

Moving to a new Mac

One export file carries the data. The rest of the work is pasting your API keys again and re-approving anything that runs a command.

On the old Mac

  1. Open App Settings → Export data → Export JSON and save the file somewhere you can reach from the new machine: AirDrop, a USB stick, a cloud folder.
  2. Make a list of your connections under App Settings → Connections. For each one you will need the original secret again — the Google Service Account JSON, the Plausible key, the Polar token. Pulsaria cannot hand them over; the Keychain entries stay on the old Mac.
  3. Note what is not in the export: theme, language, the reminder time, whether launch-at-login was on, and your auto-export settings.

On the new Mac

  1. Install Pulsaria and finish the first launch — see Install & first launch.
  2. Enter your licence key, or make sure the trial is still running. Import is blocked in read-only mode; see Trial & licence.
  3. If you keep your data in a custom folder, point Pulsaria at it before importing — see Where your data lives.
  4. App Settings → Export data → Import JSON, pick the file, then Import. On a fresh install there are no conflicts, so it is a single click.
  5. Work through the setup wizard: paste each secret, Run test, Save connection.
  6. Re-approve your Bash and HTTP KPIs. Open each one, press Edit, read the command or URL, then Approve. Until you do, the scheduler skips them with “Command not approved — please confirm in KPI settings”. See Shell commands and Custom HTTP sources.
  7. Set the things the export did not carry: theme, language, reminder, launch-at-login and the Daily auto-export card. See Settings.

Your history comes across with its original dates — entries are keyed to the local calendar day they were recorded on, not to the day you imported them.

Moving is not the same as syncing. If you want two Macs working on the same data at the same time, that is the shared-folder setup described in Where your data lives, with its own trade-offs.

Where to go next

Didn't find it?

Write to us — a real person reads every mail, usually the one who wrote the feature.

admin@one-pixel-ahead.com