Targets: Definition of target widgets calculated and seen in the app



All targets are defined in the targets.js file as an array of objects according to the Targets schema defined below. Each object corresponds to a target widget that shows in the app. The order of objects in the array defines the display order of widgets on the Targets tab. The properties of the object are used to define when the target should appear, what it should look like, and the values it will display.

See Also: Targets Overview


idstringAn identifier for the target. Used for querying task completeness.yes, unique
iconstringThe icon to show alongside the task. Should correspond with a value defined in
translation_keytranslation keyTranslation key for the title of this, but recommended
subtitle_translation_keytranslation keyTranslation key for the subtitle of this target. If none supplied the subtitle will be
percentage_count_translation_keytranslation keyTranslation key for the percentage value detail shown at the bottom of the target, eg “(5 of 6 deliveries)". The translation context has pass and total variables available. If none supplied this defaults to
contextstringA string containing a JavaScript expression. This widget will only be shown if the expression evaluates to true. Details of the current user is available through the variable
type'count' or 'percent'The type of the widget.yes
goalintegerFor targets with type: 'percent', an integer from 0 to 100. For type: 'count', any positive number. If there is no goal, put -1.yes
appliesTo'contacts' or 'reports'Do you want to count reports or contacts? This attribute controls the behavior of other attributes herein.yes
appliesToTypeIf appliesTo: 'reports', an array of form codes. If appliesTo: 'contacts', an array of contact types.Filters the contacts or reports for which appliesIf will be evaluated. For example, ['person'] or ['clinic', 'health_center']. For example, ['pregnancy'] or ['P', 'pregnancy'].no
appliesIffunction(contact, report)If appliesTo: 'contacts', this function is invoked once per contact and report is undefined. If appliesTo: 'reports', this function is invoked once per report. Return true to count this document. For type: 'percent', this controls the
passesIffunction(contact, report)For type: 'percent', return true to increment the numerator.yes, if type: 'percent'. Forbidden when groupBy is defined.
date'reported' or 'now' or function(contact, report)When 'reported', the target will count documents with a reported_date within the current month. When 'now', target includes all documents. A function can be used to indicate when the document should be counted. Default is 'reported'.no
idType'report' or 'contact' or function(contact, report)The target’s values are incremented once per unique ID. To count individual contacts that have one or more reports that apply, use 'contact'. Use 'report' to count all reports, even if there are multiple that apply for a single contact. If you need more than a single count for each applying contact or report then a custom function can be used returning an array with unique IDs — one element for each
groupByfunction(contact, report) returning stringAllows for target ids to be aggregated and scored in groups. Not required for most targets. Use with
passesIfGroupCountobjectThe criteria to determine if the target ids within a group should be counted as passingyes when groupBy is defined
passesIfGroupCount.gtenumberThe group should be counted as passing if the number of target ids in the group is greater-than-or-equal-to this valueyes when groupBy is defined
dhisobject or object[]Settings relevant to the DHIS2 Integrationno
dhis[n].dataElementstringThe hash id of a data element configured in the DHIS2 data set you’re integrating withyes
dhis[n].dataSetstringThe hash id of the data set that contains the data element you’re integrating with. If this is left undefined, the data element will appear in all data
visiblebooleanWhether the target is visible in the targets page. Default: trueno
aggregatebooleanAs of 3.9, defines whether the target will be displayed on the TargetAggregates pageno


Utility functions in the Core Framework can make common tasks much easier. These are available only for Tasks and Targets. To use the function call Utils.<function-name>(<params>), for example Utils.addDate(report.reported_date, 10).

isTimely(date, event)Returns true if the given date is after the start date and before the end date of the event.
addDate(date, days)Returns a new Date set to midnight the given number of days after the given date. If no date is given the date defaults to today.
getLmpDate(doc)Attempts to work out the LMP from the given doc. If no LMP is given it defaults to four weeks before the reported_date.
getSchedule(name)Returns the task schedule with the given name from the configuration.
getMostRecentTimestamp(reports, form)Returns the reported_date of the most recent of the reports with form ID matching the given form.
getMostRecentReport(reports, form)Like getMostRecentTimestamp but returns the report, not just the reported_date.
isFormSubmittedInWindow(reports, form, start, end)Returns true if any of the given reports are for the given form and were reported after start and before end.
isFirstReportNewer(firstReport, secondReport)Returns true if the firstReport was reported before the secondReport.
isDateValid(date)Returns true if the given date is a validate JavaScript Date.
now()Returns the current Date.
MS_IN_DAYA constant for the number of milliseconds in a day.

Please open an issue if you’d like other functions included.

Nools Extras

Helper variables and functions can be defined in nools-extras.js, which is shared by both tasks.js and targets.js. The following are global variables that can be used:

c.contactThe contact’s doc. All contacts have type of either person or place.
c.reportsAn array of all the reports submitted about the contact.
consoleUseful for outputting debugging statements. Should not be used in production code.
UtilsUseful functions across projects are available, and describe in the Utils section.

Code Samples

This sample targets.js generates three widgets, and uses functions written in the targets-extras.js file.


const { isHealthyDelivery, countReportsSubmittedInWindow } = require('./targets-extras');

module.exports = [
    id: 'births-this-month',
    type: 'count',
    icon: 'infant',
    goal: -1,
    translation_key: 'targets.births.title',
    subtitle_translation_key: 'targets.this_month.subtitle',

    appliesTo: 'reports',
    appliesIf: isHealthyDelivery,
    date: 'reported',

    id: 'delivery-with-min-1-visit',
    type: 'percent',
    icon: 'nurse',
    goal: 100,
    translation_key: 'targets.delivery_1_visit.title',
    subtitle_translation_key: 'targets.all_time.subtitle',

    appliesTo: 'reports',
    idType: 'report',
    appliesIf: isHealthyDelivery,
    passesIf: function(c, r) {
      var visits = countReportsSubmittedInWindow(c.reports, antenatalForms, r.reported_date - MAX_DAYS_IN_PREGNANCY*MS_IN_DAY, r.reported_date);
      return visits > 0;
    date: 'now',

    id: '2-home-visits-per-family',
    icon: 'home-visit',
    type: 'percent',
    goal: 100,
    translation_key: `target.2-home-visits-per-family`,
    context: 'user.role === "chw"',
    date: 'reported',

    appliesTo: 'contacts',
    appliesToType: 'person',
    idType: contact => {
      // Determines the target ids which will be in the group.
      // eg. "family1~2000-02-15" and "family1~2000-02-16"
      const householdVisitDates = new Set( => toDateString(report.reported_date)));
      const familyId =;
      return Array.from(householdVisitDates).map(date => `${familyId}~${date}`);
    groupBy: contact =>,
    passesIfGroupCount: { gte: 2 },


module.exports = {
  isHealthyDelivery(c, r) {
    return r.form === 'D' ||
        (r.form === 'delivery' && r.fields.pregnancy_outcome === 'healthy');

  countReportsSubmittedInWindow(reports, form, start, end) {
    var reportsFound = 0;
    reports.forEach(function(r) {
      if (form.indexOf(r.form) >= 0) {
        if (r.reported_date >= start && r.reported_date <= end) {
    return reportsFound;


To build your targets into your app, you must compile them into app-settings, then upload them to your instance.

medic-conf --local compile-app-settings backup-app-settings upload-app-settings

CHT Applications > Features > Targets

Dashboards to track metrics for an individual CHW or for an entire health facility

Design System > App Development

This document covers the configuration best practices of forms, tasks, targets, and contact profiles when building your own community health app.