Drıftstack docs
Docs

Profile snapshots

A profile snapshot is an immutable point-in-time record of a saved profile’s metadata — its device profile (archetype), name, and description, frozen as they were at capture time. Snapshots stay meaningful even after the source profile is renamed or deleted.

What a snapshot does NOT capture today: browser state. Cookies, localStorage, IndexedDB, and logins are not copied into the snapshot, and restoring one does not bring them back. The snapshot’s state field is empty and must not be used as a browser-state backup. To keep evolving browser state, keep the live profile itself.

The snapshot model is deliberately separate from the live profile model:

  • Profiles evolve: every session you run against a profile may mutate cookies, localStorage, IndexedDB, etc.
  • Snapshots are frozen metadata: capture an evolving profile into a named snapshot, and the snapshot’s recorded device profile / name / description remain unchanged even as the source profile keeps changing.

Restoring a snapshot creates a new profile carrying the snapshot’s frozen device profile + description — the source profile is untouched, and the new profile starts with fresh (empty) browser state.

Snapshots are captured and restored in the Driftstack desktop app (the profiles hub). The endpoints below are the API equivalents.

Capture a snapshot of a profile

POST /v1/profiles/:id/snapshots

Captures profile :id’s current metadata (device profile, name, description) as a new snapshot. No browser state is captured.

Request:

{
  "label": "post-login-known-good",
  "description": "optional, max 2048 chars"
}

Response (201):

{
  "id": "psnap_<uuid>",
  "parent_profile_id": "prof_<uuid>",
  "label": "post-login-known-good",
  "description": null,
  "parent_archetype": "iphone15_ios18_7_safari26_5",
  "parent_name": "main-account",
  "captured_at": "2026-05-10T18:00:00Z"
}

parent_profile_id, parent_archetype, and parent_name are frozen at capture time — they record the source profile’s id, device profile, and name as they were, even if the profile is later renamed or deleted.

Errors:

  • 404 not-found — the profile id doesn’t belong to the effective account (your own, or the owner you are acting as via X-Driftstack-Account).

Required scope: write or write:profiles.

List snapshots of a profile

GET /v1/profiles/:id/snapshots

Returns all snapshots of profile :id, newest first.

Response (200):

{
  "data": [
    {
      "id": "psnap_<uuid>",
      "parent_profile_id": "prof_<uuid>",
      "label": "post-login-known-good",
      "description": null,
      "parent_archetype": "iphone15_ios18_7_safari26_5",
      "parent_name": "main-account",
      "captured_at": "2026-05-10T18:00:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Pagination via ?cursor=…&limit=… follows the standard cursor shape used elsewhere in the API (data / has_more / next_cursor).

Required scope: read or read:profiles.

List all snapshots across the account

GET /v1/profile-snapshots

Returns every snapshot the effective account owns, across all profiles — your own account, or the owner you are acting as via X-Driftstack-Account. Useful for the dashboard’s “all snapshots” view or for audit reconciliation.

Response (200):

{
  "data": [
    {
      "id": "psnap_<uuid>",
      "parent_profile_id": "prof_<uuid>",
      "label": "post-login-known-good",
      "description": null,
      "parent_archetype": "iphone15_ios18_7_safari26_5",
      "parent_name": "main-account",
      "captured_at": "2026-05-10T18:00:00Z"
    }
  ],
  "has_more": false,
  "next_cursor": null
}

Each row carries parent_name (the source profile’s name frozen at capture) — handy when listing across profiles so you don’t have to issue a second fetch per row to identify the origin.

Required scope: read or read:profiles.

Get a single snapshot

GET /v1/profile-snapshots/:id

Returns one snapshot. Includes parent_profile_id so callers can follow up to fetch the underlying profile if it still exists.

Response (200):

{
  "id": "psnap_<uuid>",
  "parent_profile_id": "prof_<uuid>",
  "label": "post-login-known-good",
  "description": null,
  "parent_archetype": "iphone15_ios18_7_safari26_5",
  "parent_name": "main-account",
  "captured_at": "2026-05-10T18:00:00Z"
}

Required scope: read or read:profiles.

Restore a snapshot into a new profile

POST /v1/profile-snapshots/:id/restore

Creates a new profile carrying the snapshot’s frozen metadata — device profile and description — under the name you supply. The source profile is untouched. The new profile starts with fresh (empty) browser state: restore does not bring back cookies or logins.

Request:

{
  "name": "main-account-rolled-back"
}

Response (200):

{
  "id": "prof_<uuid>",
  "name": "main-account-rolled-back",
  "archetype": "iphone15_ios18_7_safari26_5",
  "description": null,
  "created_at": "2026-05-10T18:30:00Z",
  "last_used_at": null
}

Errors:

  • 400 validation-failed (code: "device_closed_for_new_profiles") — the snapshot’s device is closed for new profiles; nothing is created.
  • 404 not-found — the snapshot id doesn’t belong to the effective account (your own, or the owner you are acting as via X-Driftstack-Account).
  • 409 conflict — a profile with the requested name already exists.
  • 429 tier-limit — the new profile would push the account over its profile cap. Snapshot restore counts against the same cap as profile-create.

Required scope: write or write:profiles.

Delete a snapshot

DELETE /v1/profile-snapshots/:id

Permanently deletes the snapshot. The source profile is not affected. Returns 204 on success.

Errors:

  • 404 not-found — the snapshot id doesn’t belong to the effective account (your own, or the owner you are acting as via X-Driftstack-Account).

Required scope: write or write:profiles.

Audit-log emission

Only the restore operation surfaces in the account’s audit log, which you read in the Driftstack dashboard — because it creates a new profile. Capture and delete do not emit an audit entry today.

  • profile.created — fires on restore (creating the new profile). The target_resource_id is the new profile id (profile_<uuid>); the payload includes name, archetype, and restored_from_snapshot (the source snapshot id, psnap_<uuid>).

Tier-cap interaction

Snapshots themselves are NOT counted against your profile cap. You can hold many snapshots per profile, and many snapshots per account, without affecting your profile-cap budget.

Restoring a snapshot DOES count: the new profile created from the restore is subject to the same profile cap as a manually-created profile. If your tier is at-cap, the restore returns 429 tier-limit and the customer must either delete a profile first or upgrade tier.

Storage characteristics

Snapshots are metadata only, stored separately from live profiles — no browser state is stored (the state field is always empty). Each snapshot freezes the source profile’s device profile + name (parent_archetype / parent_name) at capture time, so a snapshot stays meaningful even after the parent profile is renamed or deleted. There is no per-account snapshot quota today.

SDK access

The TypeScript / Python / Go SDKs expose snapshots under the profile_snapshots resource. See the SDK quickstart for your language for the idiomatic code shape.