Data management
Importing data
Bring in patients, sessions, or notes from a CSV file, step by step.
Import patients, sessions, or notes from a CSV file — from Export your data, or a spreadsheet shaped closely enough to map in the second step. Find it from Settings, under "Import data".
The steps
- Drop in a file, or click to choose one.
- Confirm which row holds the column headers.
- Match each column in your file to a field — auto-matched already if the headers are ones this app exported.
- Review every row before anything is saved. Fix a cell directly in the table if something's wrong.
- Import — rows go in small batches, with progress shown as it goes.
- Download any rows that couldn't be imported, with the reason attached, to fix and re-upload.
Updating existing records via bulk export + re-upload
You'll basically never need to type an id yourself. Re-uploading a file that still has its id column — a full export, or the error-rows CSV described below — updates the matching existing record instead of creating a duplicate, for every row whose id matches something already in this organization. This is the main bulk-correction workflow: export everything, fix what needs fixing in a spreadsheet, and re-import the whole file. Anything whose id doesn't match — including every row if you leave the id column unmapped — creates a new record instead, so a fresh CSV you built from scratch is always additive, never overwrites something by accident.
Tip
/patients/<id>, a session's edit page is /patients/<patientId>/sessions/<id>/edit. Most people never need this — it's only relevant if you're not starting from an export.Importing sessions or notes
Sessions and notes need to know which patient they belong to. Map a patientId column if your file has one that matches a patient already in this organization; otherwise, map patientFirstName/patientLastName columns and the matching patient is found by exact name match. If neither resolves to exactly one patient, that row is flagged as an error rather than guessed at.
Note
Every session also needs an appointment — a service, provider, and location — so importing books a minimal, already-completed appointment for each row alongside the session. Map serviceId and facilityId columns if this organization has more than one service or location; if there's only one of either, it's used automatically. providerId always has to be mapped — an imported row's historical provider can't be guessed. Re-uploading a corrected file reuses each row's existing appointment rather than booking a new one every time.
Imported sessions arrive complete but unsigned, with an "Imported" badge. They don't appear in your "notes to finish" counts, because they're history from another system rather than notes you still owe. Re-uploading a corrected file updates the chart's content but never reopens or relabels it.
If you imported sessions before this change, they may still show as unfinished drafts. Owners and admins can fix that at the bottom of the import page with Mark earlier imports as imported: pick the dates you imported, review the count, and confirm. Drafts that have been edited, signed or deleted are never touched.
Importing past visits
A practice moving over from another system arrives with a history. Without it, every imported patient reads as New with no visits. Choose Past visits to bring in one row per visit: a date before today, an outcome (attended, no-show or cancelled; blank means attended) and the patient, matched the same way as sessions. If your old system only knows when someone was last seen, choose Last seen dates: one date per patient becomes a single attended visit.
Past visits are not appointments and have no chart, so nothing lands as an unsigned note. They count toward care status and the visits-attended filter, and show on the patient's page labeled Imported. Uploading the same file twice adds nothing twice. A date of today or later is kept with a warning and only counts as seen once the day has passed; bookings belong in the Appointments import.
If an import was wrong, owners and admins can remove everything it added from the Undo an import of visits or appointments list on the import page. It removes the past visits and appointments that import added, and nothing else: patients (including ones added as new), charts and notes stay. An appointment that has since gained a chart, an invoice or a form is kept, and the confirmation tells you how many.
Importing appointments
Choose Appointments to bring a whole schedule across in one file. Pick a cutoff day in the review step (it starts as today). Rows before it are kept as past visits; rows on or after it become real, confirmed appointments you can open and chart like any other. Columns are date (a time in the same cell works too), time, status, the patient, service, provider, location and an optional length in minutes.
Service, provider and location are matched by name or id. Any name in your file that isn't one of yours yet is listed once above the table; choose the match and every row using it updates. Rows still waiting on a match are held back, and the rest of the file imports. A blank time books at 09:00 with a warning, and a blank length uses the service's length.
An import accepts what already existed elsewhere. An appointment that overlaps another for the same provider is still imported, and is flagged on the calendar like a staff override. The Google Calendar busy check is skipped, and uploading the same file again skips appointments a patient already has at that time. Imported appointments get your normal reminders, but no confirmation message, and reminders whose time has already passed are not sent.
Patients that aren't found don't fail the row. The review step offers Add patients that aren't found as new patients, using the first and last name on the row; rows with the same name share one new patient. This works in every import that matches patients (sessions, notes, past visits, last seen dates and appointments).
Former patients and care ended
A migrated roster is full of people who stopped coming years ago. Left alone they all read as Lapsed, which buries the patients you actually want to win back. Two ways to fix that, both recording the same care ended fact you can add by hand:
- Status columns in a patient file. Map Status (active, or inactive, discharged, deceased and similar), optionally Status reason and Status date (blank means today). An unrecognized status isn't an error; the patient imports and the row shows a warning. Uploading the file again doesn't add the same record twice.
- Close out patients not seen in a long time, on the import page (owners and admins). Choose a date and a reason, press Preview to see how many patients it would affect, then record. It covers patients who have been seen, have nothing booked and aren't “as needed”. Each is dated their last attended visit. If anyone changed since you previewed, it asks you to preview again, and an Undo reopens everyone that sweep closed.
Care ended lifts on its own when a patient is seen again, except for deceased, which never does.
Custom fields
A session's custom field values are matched by label against this organization's current custom field definitions. A label from the file that doesn't match any current field is skipped — shown as a warning on that row, but it doesn't block the rest of the row from importing.
Patients work the same way with your patient fields: map a column to Patient field: … for a plain column, or the combined Custom fields column for the label-keyed JSON a patient export produces. Re-importing never clears a patient field you haven't mapped — values already on the patient are kept and only the mapped ones are updated.
Fixing errors
Rows with errors are never imported. After importing, download the error rows as a CSV — it's your original file's rows with an extra column explaining what went wrong, ready to correct and upload again.