History & Versions
Every campaign and every canvas has two related-but-distinct surfaces for understanding what changed and rolling it back:
- History - an event log: who did what and when (created, edited, paused, sent, archived, tagged, restored).
- Versions - immutable snapshots of the entity at a point in time, with Compare and Restore actions.
Both are accessible from the row 3-dots menu on the campaigns and canvas list pages.
History (audit log)
The History drawer renders one row per event, newest first. Each row shows the actor's name, a phrase describing the action, and a short summary derived from the changes payload - for an edit it lists the fields that changed; for a restore it shows the from/to versions; etc.
| Action | When it's logged |
|---|---|
| Created | Campaign or canvas was created (also captures channel for campaigns). |
| Edited | Save with at least one tracked field changed. |
| Published | Canvas was published (no-op when the snapshot is identical to the latest published version). |
| Sent / Launched | Campaign was launched. |
| Paused / Resumed | Status transitions on active campaigns. |
| Duplicated | New entity was duplicated from an existing one. |
| Tag changed | Tag chips were added or removed. |
| Archived | Entity was archived (also captures permanent deletes). |
| Rolled back | Restore was performed; payload includes the from/to version numbers. |
History is read-only. There is no UI to edit or delete entries - the log is for understanding what happened, not for editing the past.
Versions (snapshots)
Every save and every launch creates an immutable snapshot of the entity's editable surface (name, description, channel, targeting, schedule, variants, tags, etc. - stats stay on the live record, not on the snapshot). When two consecutive saves produce byte-identical snapshots, the second one is skipped to avoid timeline noise.
Comparing two versions
Tick two version rows and click Compare. The diff modal opens with one row per changed field, each row collapsible to inspect before/after JSON values. If the two snapshots are identical (e.g. you compared two saves that the coalescer didn't see as identical for some other reason), you'll see a "These two versions are identical" message.
Restoring a version
Click Restore on any row to bring that snapshot back. What happens next depends on the live entity's current status:
- Drafts and active items - the snapshot is copied onto the live record in place, and a new "rolled back" entry is added to the History timeline.
- Sent / completed / cancelled campaigns - terminal-state campaigns can't be edited in place (sends already happened), so Restore creates a new draft campaign with the snapshot. The launched campaign stays exactly as it was.
The principle behind this split: the live, immutable record is sacred, and edits become a fresh draft.
Best practices
- Use Restore as a safety net, not as a workflow. If you find yourself restoring versions to test variants, prefer A/B tests or duplicate-then-edit instead.
- Sample what changed before launching. Open the latest two versions in Compare before pressing send to catch unintended drift.
- Archive verbose drafts. Archived entities stay in the timeline and remain restorable; they just stop cluttering the active list.