Skip to main content

Bulk import users from CSV

Use this when onboarding a new tenant with 50+ users, or migrating from a spreadsheet-based access list.

CSV format

A header row plus one row per user:

email,full_name,role,seat_type,groups
alice@example.com,Alice Tan,editor,builder,"Finance Leadership;Dataset Authors"
bob@example.com,Bob Wijaya,viewer,viewer,"Finance Leadership"
carol@example.com,Carol Susanto,admin,admin,
ColumnRequiredNotes
emailyesMust be unique; existing users with this email are updated, not duplicated
full_nameyesFirst Last format; no other normalization
roleyesLegacy role string (admin, editor, viewer, management, cs_staff). See Permissions Reference for what each means.
seat_typeyesOne of admin, builder, analyst, viewer — orthogonal to role
groupsnoSemicolon-separated group names; empty means no group memberships beyond defaults

Save as UTF-8. Comma-delimited. Quote any field that contains a comma or semicolon (the groups column usually does).

Dry run first

Always dry-run before applying:

# CLI
honeyframe users bulk-import users.csv --dry-run

# Or via the API
curl -X POST https://platform.hubstudio.id/api/users/bulk-import \
-H "Authorization: Bearer $TOKEN" \
-F file=@users.csv \
-F dry_run=true

The dry-run output reports:

  • N users to be created
  • N users to be updated
  • N rows with validation errors (and which column)
  • Groups that would be created vs. groups that exist
  • Seat type changes that would consume additional seats

Read every line. Common errors:

  • seat_type=builder but org has no builder seats remaining — buy more seats or downgrade to analyst
  • role=editor but seat_type=viewer — viewers can't have editor role; pick a more permissive seat
  • group "Finance Leaership" not found and dry-run did not authorize creation — typo in the group name (note Leaership)

Apply

Drop the --dry-run flag once dry-run is clean. Apply produces a summary identical to dry-run plus a per-row outcome (created | updated | failed with reason).

The operation is not atomic across rows — if row 47 fails because the email is malformed, rows 1-46 still succeeded. Re-run with the failed rows (or fix and re-upload the whole file; existing users are idempotently updated).

What the import doesn't do

  • Send invitation emails — users are created with a flag indicating "needs onboarding"; trigger invitations separately via Admin → Users → Send invitations, or set --send-invitations on the import command to do both.
  • Assign permissions to specific objects — bulk-import only sets seat_type and group memberships. Object-scoped permissions (e.g. "alice can edit dashboard 42") need a separate bulk-import-permissions workflow or per-dashboard Share actions.
  • Set passwords — Honeyframe doesn't manage passwords directly; users authenticate via SSO/LDAP/email-link. If you're on a password-based deployment (rare), the import marks users as password_pending and they receive a reset link on first invitation.

See also

  • Users & Groups — the conceptual model behind seat types vs. group permissions
  • LDAP Configuration — alternative to CSV-import when the org already has a directory server