Calling Python scripts with Survey123, Integromat, and Google Cloud Functions

8177
6
01-14-2020 09:15 PM
JosephRhodes2
Occasional Contributor II
20 6 8,177

I discovered a handy workflow for calling and passing arguments to Python scripts using Survey123’s webhook capability, Integromat, and Google Cloud Functions. The possibilities are endless, but some use cases include:

  • Making scripts available and convenient to users without a Python environment on their machine
  • Calling a script each time a survey is submitted or updated (e.g., perform a field calculation)
  • Update records in a separate feature layer based on survey responses

In this example, I’ve made a simple web form and Python script that checks an ArcGIS Online org for new items and sends a raw list object of these items via email.

This post assumes basic familiarity with Survey123 Webhooks and Integromat. There are great Integromat intro posts from Ismael Chivite here and here.

 

Step 1: Create a Google Cloud Function to run your script

  1. Go to https://console.cloud.google.com/, log in with your Google account, and follow prompts to begin a Google Cloud Platform trial.
  2. You’ll be provided with a default project titled “My First Project.” From the dashboard of this project, in the Resources pane, click Cloud Functions. You can also go directly to functions at https://console.cloud.google.com/functions
  3. At the top of the page, click Create Function. Name your function and accept defaults except Runtime, which you’ll change to Python 3.7.
  4. Click the requirements.txt tab, above the code editor pane. This is where you’ll enter any Python modules required by your script that aren’t included in the standard Python distribution. For this example, we will need to add only the arcgis module.Add modules to requirements.txt
  5. Now we add our Python code! Click the main.py tab and paste your code. Be sure to wrap everything in a function, pass ‘request’ as an argument to your function, and assign variables used by the function with request.args.get(‘example’), matching the field names from the Survey123 form you’ll create in the next section. See my example below.
  6. Enter your function name under ‘Function to Execute’ and click Create. It will take a few minutes for your function to deploy.

 Python code for main.py

 

Step 2: Create and publish Survey123 

Now, let’s create a form to call the Python script.

  1. Open Survey123 Connect and create a new survey with fields for each argument you’ll be passing to the script. These field names must match what you provided to the request.args.get() method in the script – in our case, “startDate” and “toEmail”.Survey123 Connect fields
  2. Publish your survey.

 

Step 3: Set up a scenario in Integromat and connect a webhook to your Survey123 form

You’ll need to set up two modules in Integromat: The Survey123 module to watch for a new survey submission, and the HTTP module to make a request that calls the script on Google Cloud Functions and passes arguments to it.

  1. Add the Survey123 module to your scenario and connect it to your new survey as described here.
  2. Next, add the HTTP module but leave it alone for now. Connect the two modules:Integromat scenario
  3. Return to your Google Cloud Function, click the Trigger tab, and copy the URL for your function:Google Cloud Function URL
  4. Paste your URL into the HTTP module in Integromat and add a question mark at the end, followed by your first field/argument name and an equals sign, as shown below.http module integromat
  5.  Now grab your first argument from the dynamic fields window by expanding Attributes and clicking the field name:get dynamic field
  6.   Repeat for additional arguments, separating with an ampersand (&). The final URL in our example looks like this:integromat http url
     

Step 4: Call your script with the survey

  1. Turn on your Integromat scenario (or click Run Once)
  2. Open your survey in a web browser, fill in your arguments, and submit. You just called your script!
6 Comments
IsmaelChivite
Esri Notable Contributor

Joseph Rhodes‌   Thanks for sharing this. So clever!

AndrewMcAninch
New Contributor

Thanks for posting this.  I was working on getting this sort of thing working with Azure Functions, but Google Functions was a lot simpler to set up.  With a couple changes you can bypass Integromat and have the webhook send the payload directly to Google Functions.  Integromat and Microsoft Flow have never been reliable enough for us to use them in production so its great to be able to bypass that step.


The python script needs to be modified slightly to parse the payload.  Lines 9&10 should be replaced with something like:

    #convert the payload json file into a dictionary
    payload_dict = request.get_json()
    start_date = payload_dict["feature"]["attributes"]["startDate"]
    to_email = payload_dict["feature"]["attributes"]["toEmail"]

Finally, Instead of setting up Integromat:
Open survey123 website, and got into the survey's Settings > Webhooks.
Add a new webhook and use the trigger URL as the payload URL:

JosephRhodes2
Occasional Contributor II

This is excellent. Some of my workflows require Integromat to simultaneously fire other varieties of webhooks, but I do have several that only call scripts. I'm going to move the latter over to your workflow as soon as I get a chance.

YuliaMamonova
Occasional Contributor III

Thank you for sharing!

GilMastrapa
New Contributor III

Hello @JosephRhodes2  @IsmaelChivite @AndrewMcAninch  . 

Sorry for reviving this thread, i have been trying for the last 2 days to implement a direct link from a webhook to my cloud function. I followed all the steps above but it seems that something is missing. this is my simple code:

image.pngimage.png

As seen above, i just try to extract objectid from the incoming json.  My function allows for unathenticated invocations, so i hope my issue shouldn´t be token related. Here is the error on gcloud logs: 

image.png

 When using Make to capture the payload, everything works perfectly, json payload is collected in the expected shape. But in the cloud function, it keeps returning that error. Any thoughts??

image.png

 

GilMastrapa
New Contributor III

Last friday found out the problem: CORS. 

As stated here, https://community.esri.com/t5/arcgis-survey123-questions/calling-a-custom-webhook/td-p/1025136 , it seems that "The webhooks do not originate from the server, but from the client". When i tried from the android app, it worked flawlesssly. 

Here the code needed for it to work from any browser (sorry forgot to include 🙂 ). 

https://cloud.google.com/functions/docs/samples/functions-http-cors?hl=en