Proposal: Contact Tracing in OpenMRS

Tags: #<Tag:0x00007f01bff19ab0> #<Tag:0x00007f01bff199c0> #<Tag:0x00007f01bff198a8>

TLDR: See the bottom of the post for a proposed data model for contact tracing and contact cohorts in OpenMRS.

So as part of OpenMRS’s work on a response to COVID-19, there’s been an emerging consensus that we should be aiming to develop some reusable concepts, forms, reports and other components related to helping trace public health emergencies. Of course, our immediate target for this work is helping with the current COVID-19 pandemic, but, as recent history has unfortunately shown with, for example, SARS, MERS, the 2013 and 2017 Ebola outbreaks, Zika, etc. this category of problem is likely something that is going to remain with us and that global goods like OpenMRS should seek to have tools to address.

One component of this that may be useful to have are data structures to assist with contact tracing. While there are tools that are better suited to a mobile workforce (e.g., CommCare and OpenSRP, tools better suited to aggregate reporting, such as DHIS2 and even tools built precisely for this kind of surveillance, such as SORMAS), there does seem to be some role for OpenMRS to play in contact tracing, particularly in countries with wide-spread OpenMRS adoption.

The idea here wouldn’t be to turn OpenMRS into a full-blown syndromic surveillance tool, but rather to allow the capture of contact data for later follow-up and possibly recording attempts at follow-up. The vision here is to have an interface familiar to staff involved in usual point of care to capture these data for reporting upstream sources (MoHs / DHIS2 / SORMAS) for aggregation and reporting or export downstream (CommCare / OpenSRP) tools for individual follow-up.

Importantly for the design of this, a “contact” will usually contain much less information than a full patient record and those data may be less trust-worthy than those recorded for a patient (since these data are likely to be derived from patient reports rather than direct contact with the individuals in question at the point of data entry).

In some ways, it’s easy to extend the OpenMRS data model to accomodate Contacts. Pretty much all the data we would want to represent about a Contact is already representable via the Person domain. However, there are a couple of things that we may want to do that are harder to represent:

  • Cohorts (which, for our purposes are just lists of contacts with some metadata). OpenMRS, of course, has a concept of “Cohorts” in core and a Cohort module that provides a much richer data model for interacting with cohorts. Both of these Cohort models, however, are limited to representing cohorts of Patients.
  • While its possible to map Obs to Person objects, which seems to have been envisioned as a way of tracking HIV contacts, this use-case has not actually materialized, and so, for example, it is impossible to map an Encounter to a Person. Yes, this is a perhaps weird use of Encounter, but the idea would be to capture interactions with a person prior to that person becoming an actual patient, e.g., attempts (successful or otherwise) to contact a person for follow-up on possible infection.

Regarding Cohorts, I think there are two ways forward:

  1. Create a new ContactCohort that represents a Cohort of Contacts, similar, but not identical to the other OpenMRS contacts.

  2. Revise the work done on COH-24 so that the Cohort module once again supports Person as the basic unit of a Cohort, but with some addition eager fetching if the Person is a Patient.

I’m a little unsure about how to properly handle the contact encounter case.

In any case, here is a proposed UML diagram for a Contact object with its own type of Cohort:

Thoughts? Questions? Objections?


Thanks @ibacher for the detailed explanation. Is the plan to do this work in a new module, existing module, or in core?

The plan is to have this as part of a “Public Health” module for OpenMRS.

1 Like

Doing it in a module looks like a good plan.

What kind of data do you intend to capture in an encounter with a contact? Can you give some examples?

Primarily, contacts are just lists of people who might have been in contact with an infected individual. Encounters (or something like this) would, in this case, be useful to record either interactions with the person prior to their becoming a patient. I.e., called X; they will be coming in to be tested on April 23rd. Tried to call Y; the number appears to be disconnected.

I’m aware KenyaEMR has something similar setup and I am sure there are other similar models in the community, but I thought this might be a more straight-forward way to implement things.

Household module may provide additional ideas for contact tracing. It was developed to collect data in households.

@ibacher Thank you for sharing

  1. Does the Person extend the current OpenMRS person object? This makes the model easy to use
  2. I suggest you use patient instead of person so that you gain the benefit of the existing infrastructure, the differences are semantic
  3. Contact - why not change this into a contact encounter so that you can capture more details on it and leverage existing tools. There is no need for Location and Provider for an encounter since 2.0.x versions so this should work fine
  4. The above approach allows cohorts to be built for patients and communities using other attributes, but the encounter is what ties an index patient to contacts, who may later become index patients themselves by having those encounters etc

Are we yet mature with this , because it looks like many are in need of this feature urgently , I will take for Example Government of Uganda Ministry of ICT and National Guidance? I’d rather we had it as a module (Like Daniel suggested)and have it run on Refapp Earlier Versions 2.10.0 so we can Harness other features from UgandaEMR .@ibacher @ssmusoke @dkayiwa

@ssmusoke Thanks for the thoughtful responses.

The Person object there is the OpenMRS person object. I just left it in to make it clear that Contact supports more than one field. :laughing:

This is one of the key reasons I posted this here. Things are a lot easier if Contacts are Patients. I guess the real question is, does any one have an objection to modelling things this way?

The term “contact” here is borrowed from epidemiology where it refers to a person who has been in contact with an infected person. If we switch to using Patient as the base of Contact then we can easily leverage the existing encounter infrastructure as you say.

I’d be a bit worried about modelling contacts directly as an encounter with an index patient primarily because this seems to mix contact tracing information (which may not need to be kept long-term) in with clinical information (which needs to be kept long term). I suppose it makes sense to add a field tying a contact to the patient they had contact with, although I also think that there might be some flexibility in being able to define contacts where the index patient isn’t managed by the OpenMRS instance (e.g., tracking potential cases where the index patient is from outside a clinics operating area).

Thanks for that. Yes, longer-term it might be good to leverage some sort of model of “household”.

The idea is to iterate this pretty quickly so we can push it out where it can be used.

RIght now, the model is targetted at platform 2.0.5 (which corresponds to RefApp 2.6, if memory serves). We can always lower the requirements if there’s need to support versions before that.

Actually the information will be separated by the encounter type so you can even have logic to truncate the contact tracing data after a specific period of time, but provides the ability to capture alot more data in a more natural form.

Even for integration with other systems , you can transform this encounter to other formats.

The key architectural difference is later when the contact managed outside, becomes a patient at one point or another, or has some history or future that needs to be looked into

Take for example in HIV care, encounters are separated from testing, HIV enrollment, follow-up visits and if a mother from ANC and Maternity so you can look at each of those as different slices of the patient medical history.

Alright Thanks .

This was the other thing I was thinking of: that migrating a Contact -> normal Patient is a pretty trivial task whereas migrating a set of Obs -> normal Patient is… pretty custom.

I agree with @ssmusoke; it makes things much easier to use Patient as your defining base for a contact. I think it’s also the right semantic thing to do. The information you collect about a contact will be clinical and demographic patient data which can be seamlessly combined with later data if that patient has a clinical encounter, and it can also be aggregated with information about other patients in the community.

A typical use case is to start from patient A, identify patient B as a contact, monitor patient B as part of a high-risk cohort if patient A’s status suggests it, collect information occasionally about patient B as part of community health surveillance, continue documenting patient B if they get sick, and aggregate information from all contacts (or large subsets) to help define R0, identify geoclusters, etc. So, to me that means that B is indeed a patient, gets added to the patient registry right away, and the surveillance documentation events can be considered to be encounters or just off-encounter data entries.


completely agree with what @jteich said, contacts normally have a follow-up (sometimes daily) to know their status depending on the disease. This is normally collected on paper or in some cases daily calls or manual or automated SMS (e.g. using TextIt). You have surveillance officer assigned to a community that’s doing the monitoring. So the moment the contact meets case definition, this person is taken to the hospital where s/he will be recorded as a patient.

@ibacher in OpenMRS, i think we can already build contacts within using relationship and creating a couple of encounters:

  • Case reporting form (CRF) - for the person meeting case definition that collects case information + contacts
  • Contact information to add more information like when the last contact was with the suspected/confirmed case

I tried building something in OpenMRS demo to add:

  • Relationship types:

    • Index / Contact (index may not be the right term or primary - but this is the person meeting case definition and tested positive / if testing is available / or high risk
    • Contact / Index
  • THen during registration, you register the index case (without relationship) and you fill in the CRF.

  • Then register another patient and add the relationship with the index case using the relationship type ‘Index’

  • Now if you look at the relationship widget, this Contact person is now related to the Primary/Index case -

  • Now the Primary/Index case is also linked to the contact:


1 Like

@jesplana, looks great - relationship definitions and workflows seem perfect at first look.

I assume a patient can have more than one index case relationship? It will be common for a patient to be in the contact list of several case patients. Maybe there could be a way to define the date when an index-contact relationship was defined (perhaps in the first contact documentation).

@jesplana Thanks for the great suggestion on using relationships! That’s a good idea. We could possibly use that to filter down contacts for those specific forms as well. We probably would only want to define one relation type, though to keep things manageable.


Relationships actually have a start date field (not leveraged in the default registration form) we could probably leverage for recording that.

There’s still some metadata we’d probably like to collect regarding contact, e.g. type of exposure, but I suppose that can be easily captured with existing tooling.

I’m happy with this emerging consensus unless there are any objections?

/cc @burke @jdick @mksd

Or introduce Relationship Attributes. :slight_smile:

1 Like

It’s Sunday and I’m skimming through this fast, but when I first heard “contact tracing” my first reflex was also: relationships! So happy to read that this thread seems to be converging to relationships through a proper brainstorm.

1 Like

Through a module? :grimacing:

In the core platform. :slight_smile: