Received Webhook in Google App Script - Shopify not receiving my 200 OK

Michael_Holmes
New Member
12 0 0

I am using this code in Google App Script to receive a webhook created in the Shopify Admin > Notifications

The code executes in about 500 milliseconds. But I can see that Shopify is resending the post again because firebase is being triggered multiple times in succession. My webhook has been deleted 3 times because I'm not responding correctly apparently.

function doPost(e) {
//store data  in firebase
return ContentService.createTextOutput('200 OK');
}

What am I doing wrong here?

 

Documentation: https://developers.google.com/apps-script/guides/web

 

0 Likes
Michael_Holmes
New Member
12 0 0

(Further proof)
I sent a test post to my webapp using zapier and got this response which seems correct to me. Shopify seems to still be sendnig the same post multiple times.

Michael_Holmes_0-1606349504999.png

 

0 Likes
Michael_Holmes
New Member
12 0 0

any help on this? I'm returning 200 OK as text in 0.5 second but its still deleting my webhook.

0 Likes
policenauts
Pathfinder
109 6 21
0 Likes
TechGuy
Tourist
6 0 2

I'm a bit late to the party, but could it possibly be due to the way ContentService uses redirects? See here: GAS Content Service -> Redirects 

I haven't gotten far enough into using the Shopify API to test this on my own, but HtmlService a try instead: GAS Class HtmlService -> createHtmlOutput() 

0 Likes
Michael_Holmes
New Member
12 0 0

Seems this sovles my problem:

 

 

 

HtmlService.createHtmlOutputFromFile('200 OK').setSandboxMode(HtmlService.SandboxMode.IFRAME);

 

 

 

0 Likes
TechGuy
Tourist
6 0 2

Well, that's good to know! I'll keep that in mind when I'm getting set up.

Another issue is that there's no way to read HTTP headers in Google Apps Script (an annoyance of mine for a long time...), and that's where Shopify puts all the context (including the hash so you know the webhook is truly from them). I don't think sending a hash through the query parameter is secure, but at least we can add some context that way and have the script parse the query string parameter when received (eg: {{web app url}}/exec?api_version=2020-10&scope=orders_create&store=samplestore).

0 Likes
TechGuy
Tourist
6 0 2

For anyone having troubles, this worked well, and the query parameters help to identify where the webhooks are coming from. Note that there's no need for text in the HtmlService response; Shopify just looks at the headers for a 200 OK response code.

/*
Sample format: https://script.google.com/macros/s/{{SCRIPT_ID}}/exec?source=shopify&api_version=2020-10&store_name={{STORE_NAME}}&event={{EVENT_NAME}}
*/
function doPost(e) {
  
  if (e && e.postData && e.postData.type === "application/json") {
    let data = JSON.parse(e.postData.contents);
    let query = e.parameter;
    if (query.source === "shopify") {
      Logger.log("Shopify API " + query.api_version + ": Received " + query.event + " webhook data for store " + query.store_name + ".");
      // TODO: data stuff
    }
  }
  
  return HtmlService.createHtmlOutput("");
  
}

 

When I tried it with ContentService.createTextOutput() I got several hits of the doPost function indicating that Shopify retried it a few times. Checking with Chrome developer tools it appears that ContentService definitely does do a redirect that Shopify doesn't like, so it's best not to use that. ContentService doesn't sanitize the output like HtmlService does, so that's why Google needed to go through an extra step.

policenauts
Pathfinder
109 6 21

@TechGuy I'm still having trouble with this as Shopify is still sending multiple app/uninstalled webhooks, usually over the course of a few days. Here is my code, any idea what I'm doing wrong?

 

function doPost(e) {
  
  // get the payload 
  var postData = e.postData.contents;
  var json = JSON.parse(postData);
  var stringified = JSON.stringify(json, null, 2)
  
  GmailApp.sendEmail('MY EMAIL', 'webhook, someone uninstalled the app', stringified);
  
  return HtmlService.createHtmlOutput("");

}

 

0 Likes
TechGuy
Tourist
6 0 2

@policenauts, I don't see any issues with your code. It's simple and should work reliably, and even if it were to fail on Google's side, Google still sends a 200 response code.

Are you 100% sure that the webhooks are being resent, and they aren't all unique instances, possibly where the same party uninstalled the app a second time? I don't know what the payload is like from Shopify for that event, so I don't know if you can tell from that data.

0 Likes