Skip to content

Custom JSON format

This is the file format behind the JSON export, for reading or writing it with your own scripts. To move a tree in or out normally, use the Import and Export panels.

Overview

Draw My Tree uses a versioned JSON wrapper for imports and exports. Files start with a schemaVersion and a meta block, followed by a data object that holds people, relationships, and optional details, events, and media. An unknown key at the top level, in meta or in data rejects the file; an unknown field on a record is reported as a warning and not saved.

The backup .zip

The JSON export downloads as a .zip backup. It holds tree.json, the wrapper described on this page, and a media folder with each uploaded file's bytes as media/<id>.<ext>. That uploaded file's media item names it by the same relative path in url, so a backup carries no signed links. Links and text items stay as they are. Account → Download all my data writes one folder per tree in this layout, with an account.json at the top listing the trees.

The Import panel takes the .zip (one tree.json, at the top or in a single folder). It imports tree.json, then uploads each file to the person the import stored, and gives each person the picture their profileMediaId names when they have none in the tree. The 25 MB limit applies to tree.json, not to the files.

Top-level shape

FieldTypeRequiredDescription
schemaVersion"1"requiredFormat version. Currently only '1' is accepted.
metaobjectrequiredExport metadata. See Meta below.
dataobjectrequiredTree contents. See Data below.

Meta

FieldTypeRequiredDescription
exportedAtstring (ISO 8601)requiredWhen the export was produced.
appVersionstringoptionalOptional; Draw My Tree's own exports leave it out.
treeNamestringoptionalHuman-readable tree name.
homePersonIdstringoptionalThe id of the person in data.people the tree opens on. An import into a tree with no home person makes them its home person; an id that is not in the file is ignored with a warning.
placesPlaceCoordinate[]optionalMap coordinates the tree saved for its places, each { placeKey, lat, lng, source?, label? }. The placeKey is the place as people and events write it, read the same way however it is spelled. An import keeps them for every person and event written with that place, and never over a correction already saved in the tree.

Data

The data block contains five arrays. Every array must be present, even if empty.

FieldTypeRequiredDescription
peoplePerson[]requiredIndividuals in the tree.
relationshipsRelationship[]requiredParent-child and partner links.
personDetailsPersonDetails[]requiredOptional life-event places and dates per person.
eventsPersonEvent[]requiredCensus, marriage, immigration, and other dated records.
mediaPersonMedia[]requiredPhotos, portraits, and documents linked to a person or relationship.

Person

FieldTypeRequiredDescription
idstringrequiredIdentifier within the file, referenced by relationships and details. It can't contain '+'. An import stores it under the tree's own id; see Import behavior.
namestringrequiredDisplay name.
birthDatestringoptionalISO date or partial date (e.g. '1815' or '1815-12-10'), or an approximate date in GEDCOM form ('ABT 1815', 'BEF 1815-12', 'BET 1810 AND 1815'; also CAL, EST, AFT and FROM … TO). Text that isn't a readable date is kept as written.
deathDatestringoptionalSame forms as birthDate.
gender'male' | 'female' | 'other'optionalUsed for visual styling and GEDCOM export.
prefix'mr' | 'mrs' | 'ms' | 'dr' | 'rev'optionalTitle before the name, shown as Mr., Mrs., Ms., Dr. or Rev. Any other title belongs in name.
suffix'jr' | 'sr' | 'ii' | 'iii' | 'iv'optionalSuffix after the name, shown as Jr., Sr., II, III or IV.
nicknamestringoptionalThe name the person was known by, such as 'Bud'. Plain text without quotes. Keep to 60 characters; the app's editor holds you to it, an import doesn't.
surnamestringoptionalThe family-name part of name, stated when it can't be guessed: a double surname ('Fernández de Córdoba') or a surname-first name ('毛' in '毛 澤東'). A hint only; name stays the full name. Keep to 120 characters; the app's editor holds you to it, an import doesn't.
tagsstring[]optionalFree-form labels.
aliasesstring[]optionalAlternate or former names (maiden name, anglicized spelling). The name a person went by belongs in nickname.
storystringoptionalLong-form biography. Markdown is supported in the UI.
profileMediaIdstringoptionalId of the media item used as this person's portrait. The Import panel restores it after the import, for an uploaded file in a backup .zip or a link; the import API ignores it.
livingStatus'unknown' | 'living' | 'deceased'optionalWhether the person is living, as set in their details. 'unknown' leaves it to the dates.
shareVisibility'auto' | 'show' | 'hide'optionalThe person's Show on public links setting. An import by someone who can't publish keeps each person's stored setting.

Relationship

Discriminated by type.

Parent-child

FieldTypeRequiredDescription
idstringrequiredIdentifier within the file; see Import behavior.
type"parent-child"requiredDiscriminator.
parentIdstringrequiredPerson id of the parent.
childIdstringrequiredPerson id of the child.
parentType'biological' | 'adoptive' | 'foster' | 'step' | 'guardian' | 'other'optionalNature of the parental link.
confidence'certain' | 'probable' | 'possible'optionalHow certain the link is.
childOrdernumberoptionalThe child's place among the family's children, 0 for the eldest; the same on both parents' links.

Partner

FieldTypeRequiredDescription
idstringrequiredIdentifier within the file; see Import behavior.
type"partner"requiredDiscriminator.
astringrequiredOne partner's person id.
bstringrequiredThe other partner's person id.
status'married' | 'engaged' | 'partnered' | 'separated' | 'divorced'optionalCurrent state of the partnership.
startYearnumberoptionalYear the partnership began.
endYearnumberoptionalYear the partnership ended.

PersonDetails

One entry per person id. All fields except id are nullable.

FieldTypeRequiredDescription
idstringrequiredMatches a Person id.
birthDatestring | nulloptionalUsed when Person.birthDate is not set.
deathDatestring | nulloptionalUsed when Person.deathDate is not set.
birthPlacestring | nulloptionalPlace of birth.
deathPlacestring | nulloptionalPlace of death.
burialDatestring | nulloptionalDate of burial.
burialPlacestring | nulloptionalPlace of burial.
baptismDatestring | nulloptionalDate of baptism.
baptismPlacestring | nulloptionalPlace of baptism.
religionstring | nulloptionalReligious affiliation.

PersonEvent

FieldTypeRequiredDescription
idstringrequiredIdentifier within the file; see Import behavior.
type'marriage' | 'divorce' | 'census' | 'burial' | 'immigration' | 'newspaper' | 'probate' | 'property' | 'church' | 'record' | 'occupation' | 'residence'requiredEvent category.
datestring | nulloptionalSame forms as Person birthDate.
placestring | nulloptionalWhere the event occurred.
summarystring | nulloptionalShort note about the event.
urlstring | nulloptionalLink to a source record.
personIdstring | nulloptionalPerson the event is attached to.
relationshipIdstring | nulloptionalRelationship the event is attached to (e.g. marriage).

PersonMedia

FieldTypeRequiredDescription
idstringrequiredIdentifier within the file; see Import behavior.
type'photo' | 'portrait' | 'video' | 'document' | 'link' | 'text'requiredMedia category.
urlstring | nulloptionalDirect URL to the media file, or in a backup .zip the file's path in it (media/<id>.<ext>). Leave it out for 'text' items, which use body.
bodystring | nulloptionalInline content for 'text' items (transcripts, poems, recollections).
titlestring | nulloptionalShort human-readable label shown as the media's display name. Recommended under ~80 characters.
captionstring | nulloptionalLonger descriptive context, transcript snippet, or alt text. Shown beneath the title.
sourcestring | nulloptionalAttribution or archive reference.
sourceUrlstring | nulloptionalLink to the source the item was drawn from.
personIdstring | nulloptionalPerson the media is attached to.
relationshipIdstring | nulloptionalRelationship the media is attached to.

Files you uploaded through the app carry storage fields on export (storage, status, contentType, bytes, width, height). An import doesn't read them; an uploaded file comes back as an uploaded file only from a backup .zip, uploaded again from its media folder. For media you write yourself, a url (or body for text) is all you need.

Example

{
  "schemaVersion": "1",
  "meta": {
    "exportedAt": "2026-05-19T12:00:00.000Z",
    "treeName": "My Lineage",
    "homePersonId": "p1"
  },
  "data": {
    "people": [
      {
        "id": "p1",
        "name": "Ada Lovelace",
        "birthDate": "1815-12-10",
        "deathDate": "1852-11-27",
        "gender": "female",
        "tags": ["mathematician"],
        "story": "Wrote the first algorithm intended for a machine."
      },
      {
        "id": "p2",
        "name": "Byron King-Noel",
        "birthDate": "1836-05-12",
        "gender": "male"
      },
      {
        "id": "p3",
        "name": "William King-Noel",
        "birthDate": "1805-02-21",
        "gender": "male"
      }
    ],
    "relationships": [
      {
        "id": "r1",
        "type": "parent-child",
        "parentId": "p1",
        "childId": "p2",
        "parentType": "biological",
        "confidence": "certain"
      },
      {
        "id": "r2",
        "type": "partner",
        "a": "p1",
        "b": "p3",
        "status": "married",
        "startYear": 1835
      }
    ],
    "personDetails": [
      {
        "id": "p1",
        "birthPlace": "London, England",
        "religion": "Anglican"
      }
    ],
    "events": [
      {
        "id": "e1",
        "type": "census",
        "date": "1841-06-06",
        "place": "Surrey, England",
        "summary": "1841 UK Census",
        "personId": "p1"
      }
    ],
    "media": [
      {
        "id": "m1",
        "type": "portrait",
        "url": "https://example.com/ada.jpg",
        "title": "Ada at the writing desk",
        "caption": "Portrait, c. 1840, oil on canvas",
        "personId": "p1"
      }
    ]
  }
}

Import behavior

  • Files larger than 25 MB are rejected.
  • Each list holds at most 50,000 records.
  • An unknown key at the top level, in meta or in data rejects the file. An unknown field on a person, relationship, detail, event or media item (for example a typo) is reported as a warning in the import preview and is not saved.
  • A person id containing + rejects the file. A second record with an id already used in the same list is dropped with a warning, and so is a relationship that links a person to themselves.
  • A relationship, detail, event or media item that names a person or relationship not in the file is dropped.
  • A media item whose url is a media/ path (a tree.json imported without its .zip) is dropped with a warning. Import the .zip to restore the file.
  • The import API does not restore a person's profileMediaId or an uploaded file's storage fields; the Import panel restores both from a backup .zip, as above.
  • The chosen merge strategy controls how the import is reconciled with existing data. Pick a strategy in the Import sidebar before applying.
  • An import stores every record under the tree's own ids. An id the tree already holds (a re-import of this tree's own export) is kept; any other id is replaced by one derived from the tree and the file's id, so importing the same file into the same tree again finds the records the first import made. References inside the file (relationships, details, events, media and cite: links) are translated with them.
  • The import response carries an idMap with people, relationships, events and media, each mapping the file's id to the id stored. A script that goes on to update or attach to what it imported should look its ids up there rather than reuse the file's.

Last updated October 30, 2026 by Prescott Bros LLC, the makers of Draw My Tree.