The files your customers actually send
A clinic moving onto your platform exports its patient list from a practice management system that was last updated during the previous administration. The file is a fixed-width text dump with a .csv extension. MRNs come in two formats because the practice merged with another one in 2019 and never reconciled the numbering. Date of birth is MM/DD/YY, which is fine until a patient born in 1931 is parsed as a three-year-old, and a handful of rows have the DOB and the last visit date swapped.
Sex is recorded as M, F, Male, 1, and U. Diagnosis codes are ICD-9 in older rows, ICD-10 in newer ones, and a few are free text like "diabetes type 2" typed by a front desk assistant. Provider NPI is sometimes the provider's DEA number instead. Insurance member IDs contain the group number in the same cell, separated by a hyphen or a space depending on who entered it. A Consent column holds "Yes", "Y", "TRUE", "signed 2/3/22", and blanks. Every one of these rows is a real patient, and the practice needs it loaded correctly without anyone off-site seeing it.
Fields and rules that matter in EHR
| Field | What goes wrong in real files | How Dromo catches it |
|---|---|---|
| MRN | Two numbering schemes, duplicates from merged practices | Regex validator enforces the accepted pattern; unique flags collisions |
| First and last name | Combined into one cell, sometimes with "LAST, FIRST" order | Row hook splits on the comma or the space and assigns the parts correctly |
| Date of birth | Two-digit years, swapped columns, dates in the future | Date parsing with an explicit format; row hook rejects future dates and implausible ages |
| Sex | Mixed codes and spellings | Select field with allowed values; bulk transform maps the variants at once |
| ICD-10 code | ICD-9 leftovers, lowercase, missing decimal, free text | Regex validator for the ICD-10 pattern with a custom error message |
| Provider NPI | Wrong identifier in the column, transposed digits | Regex for ten digits, then a field hook runs the Luhn checksum |
| Insurance member ID | Group number appended in the same cell | Column hook separates the member ID from the group and trims both |
| Phone | Formatting noise and disconnected extensions | Column hook normalizes to E.164 |
| Address | Unit numbers in the city field, ZIP as a number with the leading zero gone | Column hooks restore ZIP formatting; required field prevents empty addresses |
| Consent flag | Free text where a boolean belongs | Checkbox type; bulk transform converts "Y", "Yes", and "TRUE" to true |
A working EHR schema
{
"fields": [
{
"label": "MRN",
"key": "mrn",
"type": "string",
"validators": [
{ "validate": "required" },
{ "validate": "unique" },
{ "validate": "regex_match", "regex": "^[A-Z]{2}\\d{7}$", "errorMessage": "MRN must be two letters followed by seven digits" }
]
},
{
"label": "Date of birth",
"key": "dob",
"type": ["date", { "outputFormat": "YYYY-MM-DD" }],
"validators": [{ "validate": "required" }]
},
{
"label": "Sex",
"key": "sex",
"type": "select",
"selectOptions": [
{ "label": "Female", "value": "F" },
{ "label": "Male", "value": "M" },
{ "label": "Unknown", "value": "U" }
]
},
{
"label": "Primary diagnosis (ICD-10)",
"key": "icd10",
"type": "string",
"validators": [
{ "validate": "regex_match", "regex": "^[A-TV-Z][0-9][0-9AB](\\.[0-9A-TV-Z]{1,4})?$", "errorMessage": "Enter a valid ICD-10-CM code, e.g. E11.9" }
]
},
{
"label": "Provider NPI",
"key": "provider_npi",
"type": "string",
"validators": [{ "validate": "regex_match", "regex": "^\\d{10}$", "errorMessage": "NPI must be exactly 10 digits" }]
},
{
"label": "Consent on file",
"key": "consent",
"type": "checkbox"
}
]
}
The NPI checksum and the not-in-the-future rule for date of birth run as hooks, since neither is expressible as a static pattern. A clinical product manager can recreate this field list in Schema Studio, including the regex patterns and the custom error text, and hand it to engineering as a finished configuration rather than a spec.
Security and deployment for EHR
Private Mode is the reason healthcare teams choose Dromo. The upload, parsing, column matching, validation, and correction all execute in the user's browser, and no protected health information is transmitted to or retained by Dromo. The clean rows go directly to your application through the onResults callback, so the only systems that ever hold PHI are the customer's machine and yours.
Dromo is HIPAA compliant and a standard Business Associate Agreement is available for teams that prefer the contractual coverage even when running in Private Mode. SOC 2 Type II certification is in place, and the full security report can be reviewed under MNDA through the Trust Center. Organizations with a policy against any third-party JavaScript touching clinical data can deploy the entire stack inside their own cloud on Kubernetes, which puts the widget, the API, and the storage under their control.
Connect it to your EHR and practice management system
In Private Mode the results path is the browser: onResults fires with an array of validated patient records, and your front end forwards them to your own API over the same authenticated channel the rest of the application uses. From there you can map to FHIR resources, write to your patient table, or queue a job that reconciles against existing charts by MRN.
Teams running the self-hosted deployment gain the server-side options as well. A webhook POST notifies your integration service when an import completes, and the REST API returns the full payload or a presigned download for batch processing. For a practice management vendor that receives nightly rosters from partner clinics, the Headless API runs the same schema without a user present and only surfaces a fix-it URL when a record fails validation and a person needs to decide.

