Skip to Content
AdministrationBulk Import (CSV)

Bulk Import from CSV

When you click Bulk import on the Users page, EUnifyer parses a CSV file and sends a set-password invitation to every row. Duplicates and invalid rows are reported back to you in the result panel; the rest of the file is processed.

File format

  • First row is the header. Column order does not matter — EUnifyer matches columns by name.
  • Only email is required. Everything else is optional.
  • Case-insensitive. Email, EMAIL, and email are all the same column.
  • Encoding: UTF-8.
  • Quoted values supported — wrap fields containing commas in "double quotes".

Recognised columns

ColumnAliases also acceptedMeaning
emaile-mail, email address, usernameThe user’s email (login). Required.
first_namefirstname, first name, given_nameGiven name
last_namelastname, last name, family_name, surnameFamily name
departmentdepte.g. Engineering, Finance
job_titletitle, rolee.g. Senior Engineer
employee_idemployee id, emp_idInternal HR identifier
role_slugEUnifyer role slug (e.g. admin, member, owner). Overrides the default-role picker for this row only.

Columns that don’t match any of the above are silently ignored, so it’s safe to drop in a wider HR export without trimming columns first.

Example file

email,first_name,last_name,department,job_title,role_slug alice@acme.example,Alice,Tester,Engineering,Senior Engineer,member bob@acme.example,Bob,Builder,Operations,Site Reliability,member chris@acme.example,Chris,Lead,Engineering,Engineering Manager,admin "diana@acme.example",Diana,"O'Connor",Finance,"Director, FP&A",member

The third row gets the admin role; everyone else falls back to the default role you picked in the dialog (typically Member).

What happens on import

For each row, EUnifyer:

  1. Normalises the email (lowercased, trimmed).
  2. Checks the org’s seat limit and refuses excess rows with an error.
  3. Looks for an existing user or pending invitation with that email.
    • If found: Duplicate — skipped, not an error. Safe to re-run.
    • If not: creates the user record, assigns the chosen role, sends a set-password email.
  4. Returns one of three statuses per row:
StatusMeaning
InvitedSet-password email sent. User row is in Pending Setup until they accept.
DuplicateEmail already exists (as a user or a pending invitation). No action taken.
ErrorInvalid email, seat limit exceeded, or another error. The detail column explains.

The aggregate counters at the top of the result panel (Invited / Skipped / Errors) tell you what to do next:

  • Mostly Invited → you’re done. Wait for users to accept.
  • Many Duplicates → this CSV has already been imported. You can close the dialog.
  • Many Errors → review the detail column, fix the file, re-run. Re-running is idempotent.

Default role

The CSV dialog has a Default role picker. Rows without a role_slug column (or with that column blank) get this role. Rows that do specify a slug always override.

Pick Member for typical employees. Don’t bulk-import people as Admin or Owner unless you mean to — those roles can manage other users, change billing, and reconfigure the workspace.

Limits

  • Seats: the import respects your plan’s seat count. Once seats are exhausted the remaining rows fail with an explicit “no seats available” detail.
  • File size: practical limit ~10,000 rows in one go. For larger lists, split the file.
  • Personal / family plans: can’t bulk-import beyond their member cap (typically 1–6). Use individual invites instead.

Troubleshooting

“No valid rows in this file. Check that the header includes ‘email’.” Your first row probably isn’t a header, or the email column is named something we don’t recognise. Add email as an explicit column or use one of the aliases listed above.

Several rows show “Duplicate” but I expected them to be new. Someone already invited those users — check Admin → Users with the Pending Setup filter, or Resend invitation instead of re-importing.

Errors with “Email already registered” — same as Duplicate; treat as a no-op.

Errors with “Failed to create Keycloak user” — the underlying identity service had a hiccup. Re-run the same file (skipped rows stay skipped, the failing ones will try again).

Some employees came in but never got the email — Check your domain’s SPF/DKIM if the mails went to spam. You can also use the Copy invitation link action on the row to grab a fresh link and hand it over directly.

What this is not

  • Not a sync — it’s a one-time invite batch. Re-running doesn’t update existing users; for ongoing roster sync use SCIM provisioning.
  • Not a permission-grant toolrole_slug picks the user’s role, but the actions that role is allowed to take live in Admin → Roles. The bulk import never edits role permissions.
  • Not for password import — users always set their own password via the link. EUnifyer never accepts pre-hashed passwords from a CSV.