# Introducing UID's for new persons and families

**URL:** <https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507>\
**Category:** Development\
**Created:** [April 9, 2023, 4:43pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507 "2023-04-09T16:43:34Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![ennoborg](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/ennoborg/32/4659_2.png) [@ennoborg](https://gramps.discourse.group/u/ennoborg)\
**Post date:** [April 9, 2023, 4:43pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/1 "2023-04-09T16:43:34Z")

</div>

Some years ago, I created a hack to add \_UID’s to all persons in my database that I added after my conversion from PAF to Gramps. It worked well, but I lost the code, and today I had a nice conversation with ChatGPT, which wrote the code to create a PAF 5 compatible UID for me. It started creating one for PAF 4, because I didn´t mention the PAF version number, but after I told it, that I wanted code for version 5, it did the job. Very nice!

But this brings up an old question: Can we discuss adding \_UID’s to new persons and families in say Gramps 5.2 or 5.3? These UID’s are a standard in commercial programs, and are also supported by Ancestry, and are easiest means to merge data after it’s made a round-trip from Gramps to Ancestry and back.

Our current import merge can´t do this, because it matches on handles, which don´t appear in GEDCOM exports. Imports from Ancestry (or other programs) generate new handles, so as far as I’m concerned, the only thing that you can rely on is the good old UID, or \_UID. It’s an official tag in GEDCOM 7, called UID, and in that version, it even shows up in events.

I also found that most of the links to this subject on our wiki stopped working:

[https://www.gramps-project.org/wiki/index.php/GEPS\_009:\_Import\_Export\_Merge#UID.2C\_GUID\_and\_UID.2C\_what\_is\_needed\_in\_Gramps.3F](https://www.gramps-project.org/wiki/index.php/GEPS_009:_Import_Export_Merge#UID.2C_GUID_and_UID.2C_what_is_needed_in_Gramps.3F)

---

<div class="post-metadata">

**Author:** ![ennoborg](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/ennoborg/32/4659_2.png) [@ennoborg](https://gramps.discourse.group/u/ennoborg)\
**Post date:** [April 9, 2023, 5:02pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/2 "2023-04-09T17:02:29Z")

</div>

Here’s part of the conversation:

 ![Schermafdruk van 2023-04-09 19-00-44](https://global.discourse-cdn.com/free1/uploads/gramps/original/2X/d/d7b0bf165cbcaee4071b3bc773f77ec0226571f4.png)

---

<div class="post-metadata">

**Author:** ![Mattkmmr](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/mattkmmr/32/410_2.png) [@Mattkmmr](https://gramps.discourse.group/u/Mattkmmr)\
**Post date:** [April 9, 2023, 5:25pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/3 "2023-04-09T17:25:42Z")

</div>

@prculley already created a pull request for UID support:

> <https://github.com/gramps-project/gramps/pull/1005>
>
> As a result of Nick's comments in #1002, I closed that PR and #1000 to create th…is more comprehensive PR.
> 
> \- This adds a uid\_list to both Person and Family objects. A single uid is attached to the object at creation (which required me to replace it on import to avoid an unnecessary extra uid).
> \- As a result, it requires a database upgrade, which code is included. If no uids were found in attributes, a single uid is added to Persons and Families.
> \- XML import/export and schema have been updated to deal with the new uid lists.
> \- The XML import move any \_UID attributes found in Persons or Families to the new uid list.
> \- GEDCOM import/export also now stores \_UID tags in the uid list and exports from there.
> \- The FindDups tool now uses the uid list to match up people with very high confidence.
> \- The FindDups tool also has a new "Very High" threshold level (the "Very High" was already in the gramps.po). This higher level will skip the more time consuming second pass of the tool if persons matching via uid are found.
> \- carefully updated the import/export tests.
> 
> Comments:
> When attempting to merge in a GEDCOM that contained \_UID for the people, with a tree that already had some of the same people, I noted that our 'Find Possible Duplicate People' was ignoring the \_UID entries. The tree also happened to have a set of actual duplicates which I could not get to show up.
> 
> On investigation, I saw that the tool did not display all possible duplicates for a single person, only the one it thought had the highest score. And it did not look at \_UID attributes at all.
> 
> This PR contains several commits;
> \- a change to GEDCOM import to remove the find\_family\_from\_handle method; this was required because it was messing up the GEDCOm import by adding an additional uid.
> \- the basic UID support
> \- a pylint on finddups
> \- the finddups patch to allow all duplicate pairs to show up
> \- the finddups patch to allow matching uid on persons to give the highest score (10).
> 
> \*\*Note:\*\* this PR is based on top of the #1010 database upgrade PR, as that is necessary to implement the upgrade. When looking at code, look at the individual commits.

---

<div class="post-metadata">

**Author:** ![ennoborg](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/ennoborg/32/4659_2.png) [@ennoborg](https://gramps.discourse.group/u/ennoborg)\
**Post date:** [April 9, 2023, 9:18pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/4 "2023-04-09T21:18:13Z")

</div>

OK, thanks. I noticed that #1000 does exactly what I want, so I will try that code in my fork.

In the code that I lost, I had a modified tool that checked for persons that had no \_UID attribute and added that. And although I can understand Nick’s objections to letting the GEDCOM export add the missing \_UID’s it is a perfect hack for me.

---

<div class="post-metadata">

**Author:** ![pgerlier](https://avatars.discourse-cdn.com/v4/letter/p/41988e/32.png) [@pgerlier](https://gramps.discourse.group/u/pgerlier)\
**Post date:** [April 10, 2023, 8:57am UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/5 "2023-04-10T08:57:15Z")

</div>

How is the \_UID made of? (I have no idea about it)

If it is created like a UUID, it is strongly dependent on the time of creation and not on person/family properties (it is not a hash for them). Then it is conceptually the same as current “handle”. Apart from the checksum addition I see no advantage or difference with the present situation. The only bonus is an additional compatibility with GEDCOM.

Now suppose you have entered a “Given Surname” person in your Gramps tree with a \_UID. Another researcher, independently from you, has committed a GEDCOM tree with \_UID. You decide to import this latter tree to merge it with yours. Since \_UID are time-based, they won’t help in identifying duplicates.

Eventually since there is nothing magical in “handles”, \_UID could replace handles everywhere in Gramps (for new objects to avoid breaking existing relationships).

---

<div class="post-metadata">

**Author:** ![ennoborg](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/ennoborg/32/4659_2.png) [@ennoborg](https://gramps.discourse.group/u/ennoborg)\
**Post date:** [April 10, 2023, 10:32am UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/6 "2023-04-10T10:32:38Z")

</div>

Yes, it’s a uuid with a checksum. Here’s the code that ChatGPT wrote for me:

```auto
import uuid

def generate_paf5_uid():
    uid = str(uuid.uuid4()).replace('-', '').upper()
    checksum = calculate_checksum(uid)
    return uid[:32] + checksum

def calculate_checksum(uid):
    # Calculate the checksum based on the first 32 characters of the UID
    uid_without_checksum = uid[:32]
    sum = 0
    for i in range(len(uid_without_checksum)):
        sum += int(uid_without_checksum[i], 16) * (i+1)
    checksum = (sum % 65536).to_bytes(2, byteorder='big').hex().upper()
    return checksum

# Example usage:
paf5_uid = generate_paf5_uid()
print(paf5_uid) # Output: "35B341D79E1B4712AE6920B92108C9A2D7825E8A29F1097DE063FE28748D47E5C24B5D5B5F5E5D5F862C8B249B02B43"

```

Note that the bot insisted that the length of the example output was right, even though It’s 95 characters, and it should be 36. That’s why I eventually told it to report to its maker.

You can see what it does when you paste the above code into a Python 3 prompt, and you can see similar code in Paul Culley’s repo, branch uid, or uid2.

Like the handles used in our own import & merge, UID’s only help to find duplicates of your own creations, like in my scenario of uploading to Ancestry, adding some new data from hints, which it now also gets from Geneanet, and then downloading an Ancestry GEDCOM. Ancestry exports those as UID, without the underscore, but they are the same format.

Note that GEDCOM 7 redefined the tag to UID, and advises to use the standard uuid format.

---

<div class="post-metadata">

**Author:** ![PLegoux](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/plegoux/32/413_2.png) [@PLegoux](https://gramps.discourse.group/u/PLegoux)\
**Post date:** [April 10, 2023, 10:37am UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/7 "2023-04-10T10:37:40Z")

</div>

Here is a description of Gedcom (U)UID including PAF’s UID:

> **[The \_UID tag](https://www.tamurajones.net/The_UIDTag.xhtml)**
>
> The \_UID tag

Yes, they are time dependant in general, depending on their version:

> **[Universally unique identifier](https://en.m.wikipedia.org/wiki/Universally_unique_identifier)**
>
> A universally unique identifier (UUID) is a 128-bit label used for information in computer systems. The term globally unique identifier (GUID) is also used.
> When generated according to the standard methods, UUIDs are, for practical purposes, unique. Their uniqueness does not depend on a central registration authority or coordination between the parties generating them, unlike most other numbering schemes. While the probability that a UUID will be duplicated is not zero, it is generally conside...

---

<div class="post-metadata">

**Author:** ![ennoborg](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/ennoborg/32/4659_2.png) [@ennoborg](https://gramps.discourse.group/u/ennoborg)\
**Post date:** [April 10, 2023, 10:45pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/8 "2023-04-10T22:45:01Z")

</div>

I just completed a simple tool that looks for persons without \_UID, lists those, and creates one for each, when the user is OK with that, using the code shown above. I did not add an automatic creation for new persons yet, because I was in a lazy mood, and didn’t bother about families either. UID’s for persons are good enough to deal with Ancestry now.

---

<div class="post-metadata">

**Author:** ![pgerlier](https://avatars.discourse-cdn.com/v4/letter/p/41988e/32.png) [@pgerlier](https://gramps.discourse.group/u/pgerlier)\
**Post date:** [April 11, 2023, 8:10am UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/9 "2023-04-11T08:10:00Z")

</div>

Since \_UIDs have no significance per se (you don’t use the internal structure of UUIDs) and only aim to provide a unique id for the record, why won’t you start from the handle which is guaranteed to be unique?

Truncate or expand it to 32 characters, add the 2-byte checksum and you have a \_UID. Since all primary objects have handles, you can repeat the process for families, events, … Thus the \_UIDs come for free and can be related to their objects.

---

<div class="post-metadata">

**Author:** ![ennoborg](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/ennoborg/32/4659_2.png) [@ennoborg](https://gramps.discourse.group/u/ennoborg)\
**Post date:** [April 11, 2023, 12:23pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/10 "2023-04-11T12:23:07Z")

</div>

You are right, and we even have a function for that:

```auto
def create_uid(self, handle=None):
    if handle:
        uid = uuid.uuid5(GRAMPS_UUID, handle)
    else:
        uid = uuid.uuid4()
    return uid.hex.upper()

```

It uses the handle if it exists, and otherwise it defaults to uuid4, which is exactly the same as the function suggested by ChatGPT.

Note that, when you import the same object back into your tree, like from an earlier backup, it will get a new handle, because handles must be unique, but the UID must be left alone, because it represents the original object.

The whole purpose of the UID is in a way that it is not related to any other thing that can change, and the handle is changed to avoid duplicates. In that case, only the UID can tell me that I imported a copy of something that I already had.

---

<div class="post-metadata">

**Author:** ![prculley](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/prculley/32/41_2.png) [@prculley](https://gramps.discourse.group/u/prculley)\
**Post date:** [April 11, 2023, 4:22pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/11 "2023-04-11T16:22:48Z")

</div>

That PR does what Nick wanted, but I don’t think it is the right answer for the long run. The UID for GEDCOM 7 has some different rules that would require changes in that PR. If/when we get serious about GEDCOM 7 support (and doing the core object upgrades to support it) we might be able to revisit this.

---

<div class="post-metadata">

**Author:** ![ennoborg](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/ennoborg/32/4659_2.png) [@ennoborg](https://gramps.discourse.group/u/ennoborg)\
**Post date:** [April 11, 2023, 4:31pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/12 "2023-04-11T16:31:11Z")

</div>

That’s right, and I am with you on that. I remade the tool to add the \_UID’s because I had the time, and ChatGPT, and it can be a big time saver for me, but it’s not fit for GEDCOM 7. I must add that I see no reason for a fast migration yet, because the other programs that I use to complement Gramps still speak 5.5.1 quite well.

---

<div class="post-metadata">

**Author:** ![jze](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/jze/32/2728_2.png) [@jze](https://gramps.discourse.group/u/jze)\
**Post date:** [April 23, 2023, 9:06am UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/13 "2023-04-23T09:06:37Z")

</div>

> [@ennoborg](#):
>
> Can we discuss adding \_UID’s to new persons and families in say Gramps 5.2 or 5.3?

It would be very beneficial if Gramps could support UIDs. Gramps is one of the few programs that do not yet support UID.

In the past there were different methods to generate a UID. In GEDCOM 7 it has now been clarified that one should use ordinary UUID, according to RFC 4122: [https://github.com/FamilySearch/GEDCOM/blob/main/specification/gedcom-03-datamodel.md#uid-unique-identifier-g7uid](https://github.com/FamilySearch/GEDCOM/blob/main/specification/gedcom-03-datamodel.md#uid-unique-identifier-g7uid)

With the UID, cross-tree connections also become possible: [GEDBAS: Ernestine Caroline KÖHLER](https://gedbas.genealogy.net/person/show/1270097354) contains a link to a different file based on the UID.

It would therefore also be good to be able to enter a UID for a person by hand.

---

<div class="post-metadata">

**Author:** ![ennoborg](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/ennoborg/32/4659_2.png) [@ennoborg](https://gramps.discourse.group/u/ennoborg)\
**Post date:** [April 23, 2023, 6:13pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/14 "2023-04-23T18:13:20Z")

</div>

> [@jze](#):
>
> It would be very beneficial if Gramps could support UIDs. Gramps is one of the few programs that do not yet support UID.

I know, and that’s why I changed GEDCOM import in such a way that \_UID lines are stored in attributes, so that they don’t get lost when you import data from other programs. You can see that, when you import data from Ancestral Quest, Legacy, PAF, RootsMagic, and many others.

And because \_UID’s are in attributes, you can also add them yourself, if you want, and they will then be exported too.

---

<div class="post-metadata">

**Author:** ![emyoulation](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/emyoulation/32/67_2.png) [@emyoulation](https://gramps.discourse.group/u/emyoulation)\
**Post date:** [April 23, 2023, 6:57pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/15 "2023-04-23T18:57:08Z")

</div>

Should we also be exploring a variant of the [GEDCOM7 tag “EXID” that relaces AFN, RFN, RIN in 5.5.1](https://gedcom.io/migrate/#afn-rfn-rin)? The spec call for it to hold the URI of the authority for the identifier in the `EXID.type` payload

Of course, these [EXID.types](https://gedcom.io/_pages/exid-type/) are intended for the standard public online genealogy databases: FamilySearch, WikiTree, FindAGrave and so forth. But it seems like the approach could be adapted to a LOCAL file or JSON Note embedded in the Tree database for private UUIDs.

Given the prevalence of linkrot over a 20 year period, I have _very_ serious misgivings about the sustainability of the proposed URL approach. There is a lot of risk in creating an external dependency.

But couldn’t the URI for that `EXID.type` payload also be stoed as a `GRAMPS://` with an internal handle to a Note of JSON type? Which could include a fallback to an external URL? In addition, there could be an interface to write the content of the JSON Note that described the particular UUID system.

One of the spots where the spec seems to fall short is in providing a direct access URL for the online database. The JSON for the FindAGrave includes a URL for their cemetery search webform: [https://www.findagrave.com/cemetery](https://www.findagrave.com/cemetery) . But it _ **could** _ have a placeholder pattern that leverages the EXID value: `https://www.findagrave.com/cemetery/[EXID.value]` so that FindAGrave Cemetery EXID.value 181852 would substitute the value into the URL to find [https://www.findagrave.com/cemetery/181852](https://www.findagrave.com/cemetery/181852)

---

<div class="post-metadata">

**Author:** ![Nick-Hall](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/nick-hall/32/95_2.png) [@Nick-Hall](https://gramps.discourse.group/u/Nick-Hall)\
**Post date:** [April 23, 2023, 11:08pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/16 "2023-04-23T23:08:33Z")

</div>

> [@emyoulation](#):
>
> Should we also be exploring a variant of the [GEDCOM7 tag “EXID” that relaces AFN, RFN, RIN in 5.5.1](https://gedcom.io/migrate/#afn-rfn-rin)?

Yes, the Gedcom IDENTIFIER\_STRUCTURE contains UID, EXID and REFN. We can probably include all these in our primary objects.

---

<div class="post-metadata">

**Author:** ![Nick-Hall](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/nick-hall/32/95_2.png) [@Nick-Hall](https://gramps.discourse.group/u/Nick-Hall)\
**Post date:** [April 23, 2023, 11:21pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/17 "2023-04-23T23:21:06Z")

</div>

> [@jze](#):
>
> In the past there were different methods to generate a UID. In GEDCOM 7 it has now been clarified that one should use ordinary UUID, according to RFC 4122

We can now use the Gedcom 7 specification as the basis for our design. I’ll have a look at this again.

---

<div class="post-metadata">

**Author:** ![DavidMStraub](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/davidmstraub/32/7_2.png) [@DavidMStraub](https://gramps.discourse.group/u/DavidMStraub)\
**Post date:** [June 12, 2025, 10:57am UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/20 "2025-06-12T10:57:57Z")

</div>

Very old thread I know, but since I’m working on a [Gedcom 7 import library](https://github.com/DavidMStraub/gramps-gedcom7), I bumped into it again.

In Gedcom 7, the following objects can have a `UID`:

- Family
- Individual
- Multimedia
- Repository
- Shared Note
- Source
- Submitter

But is it actually true that Gramps does not support a UID? In my opninion, this is the perfect use of attributes. The only thing we need to do IMHO is to define a default key for UUIDs and make sure the importers and exporters respect it.

The only small downside is that Gramps currently doesn’t allow attributes on repositories and (shared) notes, which I think it could/should, but honestly I think UIDs are mostly relevant for people and, perhaps, families. (Or places, but that’s not supported by Gedcom!)

---

<div class="post-metadata">

**Author:** ![Nick-Hall](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/nick-hall/32/95_2.png) [@Nick-Hall](https://gramps.discourse.group/u/Nick-Hall)\
**Post date:** [June 12, 2025, 1:28pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/21 "2025-06-12T13:28:13Z")

</div>

In Gedcom 7.0, an event detail structure can have `UID` tags and a place structure can have `EXID` tags.

---

<div class="post-metadata">

**Author:** ![DavidMStraub](https://yyz2.discourse-cdn.com/free1/user_avatar/gramps.discourse.group/davidmstraub/32/7_2.png) [@DavidMStraub](https://gramps.discourse.group/u/DavidMStraub)\
**Post date:** [June 12, 2025, 1:46pm UTC](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507/22 "2025-06-12T13:46:26Z")

</div>

I don’t see that in the [spec](https://gedcom.io/specifications/FamilySearchGEDCOMv7.pdf), am I missing something?

 ![image](https://global.discourse-cdn.com/free1/uploads/gramps/original/2X/c/c421297a27dfdc89656e6021575fc8196b4cd440.png)

(`EXID` is not a `UID`)

[Next page](https://gramps.discourse.group/t/introducing-uids-for-new-persons-and-families/3507.md?page=2)
