Pulling profile information

A profile is a collection of information about a specific customer. While traditional Medallia Experience Cloud reports provide aggregated data across multiple customers, profiles provide a look at data and trends for individual people that have interacted with your company.

Our customer profiles are up to date, and provide the latest information on a customer. Use this information to enrich other survey responses such as digital data, or to enrich data outside Medallia and display it on external systems.

To increase the speed at which Experience Cloud can process profile data, Profiles do not rely directly on feedback record data tables. Instead, they use one or more Experience programs, each containing schemas that map profile-specific data in feedback records to new tables used by Profiles. Make sure you have an Experience program created in your instance before working with Profiles.

Important: As of iOS15, Apple devices obfuscate the user’s IP address when using the Mail app. The schemas used for profiles include one or more configurable customer identifiers. If the only customer identifier configured is for the customer email address, multiple profiles might be created for the same user. To avoid this, always configure at least one other identifier besides email address.

Use Query API to fetch customer information by requesting the customerSchema and customers nodes. Pull core information, such as first name, last name, email, and phone number, for the customers in your programs, or bring detailed demographic information.

Inspecting the customer schema

Inspect the customer metadata fields to determine which customer attributes are available:

Example - Inspect the customer schema

query contactMetadata {
  customerSchema {
    attributes {
      nodes {
        key
        name
        containsPii
        type
      }
      pageInfo {
        hasNextPage
        endCursor
      }
    }
  }
}

By default, Query API will fetch up to 30 attributes, but that number can be increased by passing in a first argument in the attributes operation. Use this option when you expect that the attribute list will have to be paginated.

Sample response

{
  "data": {
    "customerSchema": {
      "attributes": {
        "nodes": [
          {
            "key": "age_group",
            "name": "Age Group",
            "containsPii": false,
            "type": "ENUM"
          },
          {
            "key": "country",
            "name": "Country",
            "containsPii": false,
            "type": "STRING"
          },
          {
            "key": "customer_tier",
            "name": "Customer Tier",
            "containsPii": false,
            "type": "ENUM"
          },
          {
            "key": "customer_type",
            "name": "Customer Type",
            "containsPii": false,
            "type": "ENUM"
          },
          {
            "key": "email",
            "name": "Email",
            "containsPii": true,
            "type": "EMAIL"
          },
          {
            "key": "first_name",
            "name": "First name",
            "containsPii": true,
            "type": "STRING"
          },
          {
            "key": "language",
            "name": "Language",
            "containsPii": false,
            "type": "ENUM"
          },
          {
            "key": "last_name",
            "name": "Last name",
            "containsPii": true,
            "type": "STRING"
          },
          {
            "key": "loyalty_number",
            "name": "Loyalty Number",
            "containsPii": false,
            "type": "ENUM"
          },
          {
            "key": "phone",
            "name": "Phone",
            "containsPii": true,
            "type": "STRING"
          }
        ],
        "pageInfo": {
          "hasNextPage": false,
          "endCursor": null
        }
      }
    }
  },
  "errors": null,
  "_links": null,
  "_allowed": [
    "POST",
    "GET"

To get recently updated contacts or surveys, inspect the customer timeline. For more information see Retrieving customer timeline.

Querying customer information

Fetch contact information using customer attributes querying the customers node.

To see more information on how to query the feedback node to get customer IDs, see section Retrieving feedback information.

To see more information on how to query the invitations node to get customer IDs, see section Retrieving invitation information.

Example - Fetch contact information

query retrieveContactInfo {
 customers(ids: 45) {
   nodes {
     id
     First_name: value(src: {attributeKey: "first_name"})
     Last_name: value(src: {attributeKey: "last_name"})
     Language: value(src: {attributeKey: "language"})
     Phone: value(src: {attributeKey: "phone"})
     Loyalty_number: value(src: {attributeKey: "loyalty_number"})    
   }
 }
}

Sample response

{
  "data": {
    "customers": {
      "nodes": [
        {
          "id": "45",
          "First_name": "Brian",
          "Last_name": "Weaver",
          "Language": null,
          "Phone": "(573)  881-4892",
          "Loyalty_number": null
        }
      ]
    }
  },
  "errors": null,
  "_links": null,
  "_allowed": [
    "POST",
    "GET"
  ]
}

A similar query using the valueList operation would be:

Example - Fetch contact information

query retrieveContactInfo {
 customers(ids: 45) {
   nodes {
     id    
     valueList(srcs: [{attributeKey: "first_name"}, {attributeKey: "last_name"}, {attributeKey: "language"}, {attributeKey: "phone"} {attributeKey: "lotalty_number"}])
   }
 }
}

Sample response

{
  "data": {
    "customers": {
      "nodes": [
        {
          "id": "45",
          "valueList": [
            "Brian",
            "Weaver",
            null,
            "(573)  881-4892",
            null
          ]
        }
      ]
    }
  },
  "errors": null,
  "_links": null,
  "_allowed": [
    "POST",
    "GET"
  ]
}

Filter for entries that match a specific value

Additionally, you can query the customers node for entries that match a specific attribute, such as the email address.

Example - Filter by email address

query customersByEmail {
  customers(filter:{attributeKey: "email", in: "2162028504776820@example.com"}) {
    nodes {
      id
      value(src:{attributeKey: "email"})
      feedback {
        nodes {
          id
          responseDate: fieldValue(fieldId: "e_responsedate")
          status: fieldValue(fieldId: "e_status")
        }
      }
    }
  }
}

Sample response

{
  "data": {
    "customers": {
      "nodes": [
        {
          "id": "5534",
          "value": "2162028504776820@example.com",
          "feedback": {
            "nodes": [
              {
                "id": "79714",
                "responseDate": "2019-01-04 00:00:00",
                "status": "COMPLETED"
              }
            ]
          }
        }
      ]
    }
  },
  "errors": null,
  "_links": null,
  "_allowed": [
    "POST",
    "GET"
  ]
}

There is more than one option to retrieve data from the customers node:

Example -  Retrieve contact information

query retrieveContactInfo {
customers (filter:{attributeKey: "email", in: "2162028504776820@example.com"}) {
  nodes {
    id
    First_name: value(src: {attributeKey: "first_name"})
    Last_name: value(src: {attributeKey: "last_name"})
    Language: value(src: {attributeKey: "language"})
    Phone: value(src: {attributeKey: "phone"})
    Loyalty_number: value(src: {attributeKey: "loyalty_number"})   
  }
 }
}

Sample response

{
 "data": {
   "customers": {
     "nodes": [
       {
         "id": "5538",
         "First_name": "Laura",
         "Last_name": "Cunningham",
         "Language": null,
         "Phone": "(698)  666-3711",
         "Loyalty_number": null
       }
     ]
   }
 },
 "errors": null,
 "_links": null,
 "_allowed": [
   "POST",
   "GET"
 ]
}

Retrieving customer timeline

Query the customers node to retrieve the timeline for a specific customer to get signals associated with the contact ID.

Example - Retrieve timeline

query customerTimeline {
  customers (ids: 45){
    nodes {
      id
      valueList(srcs: [{attributeKey: "first_name"}, {attributeKey: "last_name"}])
      feedback {
        nodes {
          responseDate: fieldValue(fieldId: "e_responsedate")
          status: fieldValue(fieldId: "e_status")
        }
      }
    }
  }
}

Sample response

{
  "data": {
    "customers": {
      "nodes": [
        {
          "id": "45",
          "valueList": [
            "Brian",
            "Weaver"
          ],
          "feedback": {
            "nodes": [
              {
                "responseDate": "2020-05-20 03:59:07",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2020-08-14 21:21:41",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2020-03-30 23:10:21",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2020-05-08 16:47:02",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2020-04-17 06:44:16",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2020-05-23 10:35:28",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2020-08-23 13:56:33",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2020-05-24 13:20:26",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2020-11-30 00:50:37",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2020-10-29 07:35:29",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2019-12-24 05:18:09",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2019-12-07 00:10:53",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2019-09-21 02:10:34",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2019-08-21 04:21:30",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2019-03-20 22:27:52",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2019-01-10 13:35:02",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2019-04-18 15:36:26",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2019-06-13 20:12:34",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2019-11-17 04:19:50",
                "status": "COMPLETED"
              },
              {
                "responseDate": "2019-03-10 05:23:43",
                "status": "COMPLETED"
              }
            ]
          }
        }
      ]
    }
  },
  "errors": null,
  "_links": null,
  "_allowed": [
    "POST",
    "GET"
  ]
}

Retrieving feedback information

Use the feedback node to retrieve feedback entries that have been processed for contact data. use the e_initialfinishdate field which is guaranteed to be monotonously increasing and can be leveraged to incrementally fetch record data.

Fetch pages with new records using 2 parameters:
  • the latest timestamp

  • the number of records to skip

Example - Retrieve records processed for contact data

query Responses($lastDate: String!, $skip: ID!, $PAGE_SIZE: Int!) {
 feedback(
   first: $PAGE_SIZE
   after: $skip
   filter: {
     and: [
       { fieldIds: "e_initialfinishdate" gte: $lastDate }
       { fieldIds: "e_contact_handle_id", isNull: false }
     ]
   }
   orderBy: [
     { fieldId: "e_initialfinishdate" direction: ASC }
     { fieldId: "a_surveyid" direction: ASC }
   ]
 ) {
   nodes {
     id
     ts: fieldValue(fieldId: "e_initialfinishdate")
     cid: fieldValue(fieldId: "e_contact_handle_id")
   }
 }
}

Sample variables

{
   "lastDate": "2001-01-01",
   "skip": "0",
   "PAGE_SIZE": 5
}

Sample response

{
   "data": {
     "feedback": {
       "nodes": [
         {
           "id": "37714158",
           "ts": "2020-03-17 01:46:22",
           "cid": "41380"
         },
         {
           "id": "37715237",
           "ts": "2020-03-17 03:06:23",
           "cid": "41399"
         },
         {
           "id": "37715999",
           "ts": "2020-03-17 03:23:22",
           "cid": "41763"
         },
         {
           "id": "37716179",
           "ts": "2020-03-17 03:29:22",
           "cid": "41421"
         },
         {
           "id": "37717077",
           "ts": "2020-03-17 04:43:22",
           "cid": "41768"
         }
       ]
     }
   },
   "errors": null,
   "_links": null,
   "_allowed": [
     "POST",
     "GET"
   ]
}

To restrict the records – to a unit for instance – use a filter like:

   filter: {
     and: [
       { fieldIds: "e_initialfinishdate" gte: $lastDate }
       { fieldIds: "e_contact_handle_id", isNull: false }
       { fieldIds: "e_unitid", in: [ $unitId ] }
     ]
   }

Retrieving invitation information

Use a similar approach for invitations (whether sampled or not) but using on e_creationdate rather than the initial finish date.

Sample request - Retrieve records for contact data

query Invitations($lastDate: String!, $skip: ID!, $PAGE_SIZE: Integer!) {
 invitations(
   first: $PAGE_SIZE
   after: $skip
   filter: {
     and: [
       { fieldIds: "e_creationdate" gte: $lastDate }
       { fieldIds: "e_contact_handle_id", isNull: false }
     ]
   }
   orderBy: [
     { fieldId: "e_creationdate" direction: ASC }
     { fieldId: "a_surveyid" direction: ASC }
   ]
 ) {
   nodes {
     id
     ts: fieldValue(fieldId: "e_creationdate")
     cid: fieldValue(fieldId: "e_contact_handle_id")
   }
 }
}

Querying aggregate metrics

Use the aggregate and aggregateTable operations to query for aggregate metrics.

To query R-Fields, like the example below, use the custom metric. For more details about aggregate operations, see Aggregations.

Sample request - Retrieve aggregate metrics

query name {
  customers(query: "gale.johns") {
    nodes {
      id
      firstname
      lastname
      email
      totalSpend: aggregate(
        definition: {
          data: { source: INVITATIONS }
          metric: {
            custom: { field: { id: "r_bp_total_spend_one_channel" } }
          }
        }
      )
      numberOfFlights: aggregate(
        definition: {
          data: { source: INVITATIONS }
          metric: { custom: { field: { id: "r_bp_number_of_flights" } } }
        }
      )
    }
  }
}

Sample response

{
  "data": {
    "customers": {
      "nodes": [
        {
          "id": "1",
          "firstname": "Gale",
          "lastname": "Johns",
          "email": "gale.johns@merlin.example.com",
          "totalSpend": 7948.38,
          "numberOfFlights": 12
        },
        {
          "id": "2854549",
          "firstname": "Gale",
          "lastname": "Johns",
          "email": "gale.johns@expdemo.example.com",
          "totalSpend": 957.86,
          "numberOfFlights": 1
        }
      ]
    }
  },
  "errors": null,
  "_links": null,
  "_allowed": [
    "POST",
    "GET"
  ]
}