We value your privacy

We use cookies to enhance your browsing experience, serve personalised ads or content, and analyse our traffic. By clicking "Accept All", you consent to our use of cookies.

CustomiseReject AllAccept All

Powered by [Visit CookieYes website](https://www.cookieyes.com/product/cookie-consent/?ref=cypbcyb&utm_source=cookie-banner&utm_medium=fl-branding)

Customise Consent Preferences

We use cookies to help you navigate efficiently and perform certain functions. You will find detailed information about all cookies under each consent category below.

The cookies that are categorised as "Necessary" are stored on your browser as they are essential for enabling the basic functionalities of the site. ... Show more

NecessaryAlways Active

Necessary cookies are required to enable the basic features of this site, such as providing secure log-in or adjusting your consent preferences. These cookies do not store any personally identifiable data.

No cookies to display.

Functional

Functional cookies help perform certain functionalities like sharing the content of the website on social media platforms, collecting feedback, and other third-party features.

- Cookie

\_octo

- Duration

1 year

- Description

No description available.

- Cookie

logged\_in

- Duration

1 year

- Description

No description available.

- Cookie

VISITOR\_PRIVACY\_METADATA

- Duration

6 months

- Description

YouTube sets this cookie to store the user's cookie consent state for the current domain.

- Cookie

\_\_Secure-YNID

- Duration

6 months

- Description

YouTube cookie used to protect user security and prevent fraud, especially during the login process.

- Cookie

\_\_Secure-ROLLOUT\_TOKEN

- Duration

6 months

- Description

YouTube sets this cookie to manage feature rollout and experimentation. It helps Google control which new features or interface changes are shown to users as part of testing and staged rollouts, ensuring consistent experience for a given user during an experiment.

- Cookie

\_\_Secure-YEC

- Duration

past

- Description

Description is currently not available.

- Cookie

\_gh\_sess

- Duration

session

- Description

GitHub sets this cookie for temporary application and framework state between pages like what step the user is on in a multiple step form.

- Cookie

YSC

- Duration

session

- Description

YSC cookie is set by Youtube and is used to track the views of embedded videos on Youtube pages.

- Cookie

VISITOR\_INFO1\_LIVE

- Duration

6 months

- Description

A cookie set by YouTube to measure bandwidth that determines whether the user gets the new or old player interface.

- Cookie

ytidb::LAST\_RESULT\_ENTRY\_KEY

- Duration

Never Expires

- Description

The cookie ytidb::LAST\_RESULT\_ENTRY\_KEY is used by YouTube to store the last search result entry that was clicked by the user. This information is used to improve the user experience by providing more relevant search results in the future.

Analytics

Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics such as the number of visitors, bounce rate, traffic source, etc.

- Cookie

\_ga

- Duration

1 year 1 month 4 days

- Description

Google Analytics sets this cookie to calculate visitor, session and campaign data and track site usage for the site's analytics report. The cookie stores information anonymously and assigns a randomly generated number to recognise unique visitors.

- Cookie

\_ga\_\*

- Duration

1 year 1 month 4 days

- Description

Google Analytics sets this cookie to store and count page views.

Performance

Performance cookies are used to understand and analyse the key performance indexes of the website which helps in delivering a better user experience for the visitors.

No cookies to display.

Advertisement

Advertisement cookies are used to provide visitors with customised advertisements based on the pages you visited previously and to analyse the effectiveness of the ad campaigns.

No cookies to display.

Uncategorised

Other uncategorised cookies are those that are being analysed and have not been classified into a category as yet.

No cookies to display.

Reject AllSave My PreferencesAccept All

Powered by [Visit CookieYes website](https://www.cookieyes.com/product/cookie-consent/?ref=cypbcyb&utm_source=cookie-banner&utm_medium=sl-branding)

[Skip to main content](/content/docs/bots/bot-for-questionnaire-response#__docusaurus_skipToContent_fallback/index.html)

On this page

Bots are an advanced Medplum feature that enable complex workflows.

One of the most powerful uses is to combine Bots with [Questionnaires](/content/docs/api/fhir/resources/questionnaire/index.html)

A FHIR [Questionnaire](/content/docs/api/fhir/resources/questionnaire/index.html) is a customizable form. You can add custom questions, question types, multiple choice options, etc. You can think of a FHIR Questionnaire as a healthcare-specific Google Forms or Survey Monkey.

Connecting a Bot to a Questionnaire enables custom workflows that you control top to bottom.

## Example uses [​](/content/docs/bots/bot-for-questionnaire-response\#example-uses "Direct link to Example uses"/index.html)

Consider some of these Bot and Questionnaire use cases:

- Patient registration - Create a Patient plus initial [Appointment](/content/docs/api/fhir/resources/appointment/index.html) or [ServiceRequest](/content/docs/api/fhir/resources/servicerequest/index.html)
- Observation entry - From one form, create many [Observation](/content/docs/api/fhir/resources/observation/index.html) and [DiagnosticReport](/content/docs/api/fhir/resources/diagnosticreport/index.html) resources
- Quick ordering - Create shortcut forms for common orders or workflows

These capabilities would normally require writing custom code, HTTP servers, webhooks, and managing credentials for a separate service.

By using Bots, the entire logic is self contained and managed in one place. Like all FHIR resources in Medplum, the Bot resource is versioned with full history tracking, so you can see exactly what changed over time.

## Patient registration example [​](/content/docs/bots/bot-for-questionnaire-response\#patient-registration-example "Direct link to Patient registration example"/index.html)

Let's create a simple example Patient Registration form to see how this works. We'll write a simple questionnaire to collect information from a patient, and then write a Bot that creates the corresponding [Patient](/content/docs/api/fhir/resources/patient/index.html) and [ServiceRequest](/content/docs/api/fhir/resources/servicerequest/index.html) resources.

### 1\. Create the Questionnaire [​](/content/docs/bots/bot-for-questionnaire-response\#1-create-the-questionnaire "Direct link to 1. Create the Questionnaire"/index.html)

Our first step will be to create the questionnaire in the Medplum App

1. Log into the [Medplum App](https://app.medplum.com/)
2. Click "Questionnaire" on the left sidebar or navigate to [app.medplum.com/Questionnaire](https://app.medplum.com/Questionnaire)
3. Click "new"
4. This brings you to the default Resource editor. However, we are going to use an alternate method to author the Questionnaire. For now:
1. Enter a "Title" for your new Questionnaire
2. Scroll to the bottom of the page and click "OK"
5. Once you click "OK", navigate to the "Builder" Tab to actually create the Questionnaire

### 2\. Edit the Questionnaire [​](/content/docs/bots/bot-for-questionnaire-response\#2-edit-the-questionnaire "Direct link to 2. Edit the Questionnaire"/index.html)

On the "Builder tab", you can add items to the Questionnaire with a Google Forms-like interface.

Click the "Add Item" link at the bottom of the page to add each question. For each question, you will have to set the following properties:

- **Type**: Select the question type from the dropdown
- **Text:** The displayed text for the question
- **Link Id**: The machine-readable identifier for the question. While Medplum supplies a default `linkId`, **_we highly recommend that users supply their own ids_** that are semantically relevant in their particular context.

For this sample patient registration form, we will create five questions:

- First Name (type: `string`, linkId: `firstName`)
- Last Name (type: `string`, linkId: `lastName`)
- Email (type: `string`, linkId: `email`)
- Phone (type: `string`, linkId: `phone`)
- Reason for Visiting (type: `choice`, linkId: `reasonForVisit`)

### 3\. Submit the Form [​](/content/docs/bots/bot-for-questionnaire-response\#3-submit-the-form "Direct link to 3. Submit the Form"/index.html)

When you’re done, click on the “Preview” tab to see how your questionnaire will look.

At the top, you will see this notice:

To actually fill out the form, you will need to click on this link to be taken to the "form" page for your Questionnaire. You can also share this link with other users.

Click on your form, fill it out, and click “Submit”.

Now we’ll inspect the data. Click on the “Review your Answers” link.

Let’s take a look at the resource that is created:

- The resulting resource is of type [QuestionnaireResponse](/content/docs/api/fhir/resources/questionnaireresponse/index.html)
- The main property of interest is called `item`, all the form questions as well as their answers.
- Each item has a `linkId` that you set in the builder, as well an answer array. Most of the time this array will contain 0 or 1 elements, but it could contain multiple elements in the case of multi-choice fields
- The `questionnaire` property contains a reference to the original questionnaire that generated this response

### 4\. Write the Bot [​](/content/docs/bots/bot-for-questionnaire-response\#4-write-the-bot "Direct link to 4. Write the Bot"/index.html)

Next, we'll write a Bot that creates a [Patient](/content/docs/api/fhir/resources/patient/index.html) and [ServiceRequest](/content/docs/api/fhir/resources/servicerequest/index.html) based on the user's response. To learn how to set up a new Bot, see the [Bot Basics tutorial](/content/docs/bots/bot-basics/index.html)

To parse out the answers in the ' [QuestionnaireResponse](/content/docs/api/fhir/resources/questionnaireresponse/index.html), we'll use the [`getQuestionnaireAnswers`](/content/docs/sdk/core.getquestionnaireanswers) utility function. This function returns a map from the question's `linkId` to the response.

```ts
// Use the getQuestionnaireAnswers utility function to convert the response into

// a map of [linkId, answer] pairs.

const response = event.input as QuestionnaireResponse;

const answers = getQuestionnaireAnswers(response);

// Read out the user's answers into separate variables

// Here we provide default answers if the user's answer is 'undefined'

const firstName = answers['firstName']?.valueString || '';

const lastName = answers['lastName']?.valueString || '';

const email = answers['email']?.valueString || 'No Email Given';

const phone = answers['phone']?.valueString || 'No Phone Number Given';

const reasonForVisiting = answers['reasonForVisit']?.valueString || 'No Reason Given';
```

We can combine this with the [`medplum.createResource`](/content/docs/sdk/core.medplumclient.createresource) method to create the [Patient](/content/docs/api/fhir/resources/patient/index.html) and [ServiceRequest](/content/docs/api/fhir/resources/servicerequest/index.html) . The final Bot then looks like this:

```ts
import { BotEvent, MedplumClient, getQuestionnaireAnswers, createReference } from '@medplum/core';

import { QuestionnaireResponse, Patient, ServiceRequest } from '@medplum/fhirtypes';

export async function handler(medplum: MedplumClient, event: BotEvent): Promise<any> {

const response = event.input as QuestionnaireResponse;

// Use the getQuestionnaireAnswers utility function to convert the response into

// a map of [linkId, answer] pairs.

const answers = getQuestionnaireAnswers(response);

// Read out the user's answers into separate variables

// Here we provide default answers if the user's answer is 'undefined'

const firstName = answers['firstName']?.valueString || '';

const lastName = answers['lastName']?.valueString || '';

const email = answers['email']?.valueString || 'No Email Given';

const phone = answers['phone']?.valueString || 'No Phone Number Given';

const reasonForVisiting = answers['reasonForVisit']?.valueString || 'No Reason Given';

// Create the patient

const patient = await medplum.createResource<Patient>({

resourceType: 'Patient',

name: [\
\
      {\
\
        given: [firstName],\
\
        family: lastName,\
\
      },\
\
    ],

telecom: [\
\
      {\
\
        system: 'email',\
\
        value: email,\
\
      },\
\
      {\
\
        system: 'phone',\
\
        value: phone,\
\
      },\
\
    ],

});

console.log('Created Patient ', patient.id);

// Create the Service Request

const serviceRequest = await medplum.createResource<ServiceRequest>({

resourceType: 'ServiceRequest',

status: 'active',

intent: 'order',

subject: createReference(patient),

reasonCode: [\
\
      {\
\
        text: reasonForVisiting,\
\
      },\
\
    ],

});

console.log('Created ServiceRequest ', serviceRequest.id);

}
```

### 5\. Create the Subscription [​](/content/docs/bots/bot-for-questionnaire-response\#5-create-the-subscription "Direct link to 5. Create the Subscription"/index.html)

The last step is to have your Bot listen to your Questionnaire responses.

1. Go to you the your Questionnaire's page in the [Medplum App](https://app.medplum.com/Questionnaire)
2. Click on the the "Bots" tab
3. Start typing the name of your Bot.
4. When your Bot appears in the type ahead, select it and click "Connect"

Ordering of Subscription Events

Because of the variable timing and routes of http traffic, the Medplum server cannot guarantee the order in which [`Subscription`](/content/docs/api/fhir/resources/subscription/index.html) webhooks are received by the client.

### 6\. Watch it work [​](/content/docs/bots/bot-for-questionnaire-response\#6-watch-it-work "Direct link to 6. Watch it work"/index.html)

Now if you [submit the form](/content/docs/bots/bot-for-questionnaire-response#3-submit-the-form/index.html) again, you'll notice that a new [Patient](/content/docs/api/fhir/resources/patient/index.html) and [ServiceRequest](/content/docs/api/fhir/resources/servicerequest/index.html) have been created.

## Conclusion [​](/content/docs/bots/bot-for-questionnaire-response\#conclusion "Direct link to Conclusion"/index.html)

The Bots + Questionnaire patten is a powerful way to use Medplum to automate your medical workflows. While this was a very simple example, you can check out the [Medplum Demo Bots repo](https://github.com/medplum/medplum-demo-bots/) for more examples on how to use Bots.

- [Example uses](/content/docs/bots/bot-for-questionnaire-response#example-uses/index.html)
- [Patient registration example](/content/docs/bots/bot-for-questionnaire-response#patient-registration-example/index.html)
  - [1\. Create the Questionnaire](/content/docs/bots/bot-for-questionnaire-response#1-create-the-questionnaire/index.html)
  - [2\. Edit the Questionnaire](/content/docs/bots/bot-for-questionnaire-response#2-edit-the-questionnaire/index.html)
  - [3\. Submit the Form](/content/docs/bots/bot-for-questionnaire-response#3-submit-the-form/index.html)
  - [4\. Write the Bot](/content/docs/bots/bot-for-questionnaire-response#4-write-the-bot/index.html)
  - [5\. Create the Subscription](/content/docs/bots/bot-for-questionnaire-response#5-create-the-subscription/index.html)
  - [6\. Watch it work](/content/docs/bots/bot-for-questionnaire-response#6-watch-it-work/index.html)
- [Conclusion](/content/docs/bots/bot-for-questionnaire-response#conclusion/index.html)
