Skip to main content

New: Remote fetch in Scripting App


Happy February! We’re excited to announce that our new remoteFetchAsync function is now live within the Scripting App.


One of the most common issues we see users run into when writing scripts is in trying to use the fetch API to communicate with an external service. Because Scripting App scripts run directly in the user’s browser, fetch requests will be blocked by the browser if the target server doesn’t support Cross-Origin Resource Sharing (CORS).


The new remoteFetchAsync method transmits the request from Airtable’s own servers rather from the user’s browser, thereby getting around CORS issues. remoteFetchAsync works very similarly to fetch and expects the same inputs, except for a handful of “gotchas” stemming from the fact that this is run from a backend.


Resources to get started:



  1. Read documentation: Learn about the functionality of remoteFetchAsync here.

  2. Share your script template with Airtable customers: Already built a script that utilizes backend fetch? Submit here to get it listed in the Airtable marketplace.


Let us know if you have any questions or feedback in the comments below!

26 replies

  • Inspiring
  • 3264 replies
  • February 4, 2021

One - are there any remote fetch limits or quotas?


  • Participating Frequently
  • 93 replies
  • February 4, 2021

Thanks !!! 👏 🎉


I really appreciate this upgrade;


I had to use proxies tons of times, and this change would save my clients and me a lot of time.


In the past, my clients were forced to set up AWS | pipedream | Heroku accounts just for using the scripting app (it didn´t make sense for a non-technical user).


Also, I was planning to submit some scripts, but some of them required a proxy; now, they don´t.


Opportunity: Avoid the restriction of FormData (this is also restricted in automation scripts).


  • Inspiring
  • 3264 replies
  • February 4, 2021


The follow redirect mode is not supported. Only error and manual are supported. As manual returns an ‘opaque’ response in order to respect atomic HTTP redirect handling, it’s effectively impossible to follow redirects at present.



Sorry, second question - doesn’t this rule out using remote fetch with the entirety of Google APIs since redirection is a fundamental security aspect of Google Cloud Platform and many other API platforms?


@Taylor_Savage can you point me in the right direction? If I used this code in an automation block, how would I rewrite it to use in an app scripting block? Thanks


let response = await fetch(‘https://api.companieshouse.gov.uk/company/’ + {COMPANY_NUMBER}, {

method: ‘GET’,

headers: {

‘Authorization’ : {API_KEY},

‘Content-Type’: ‘application/json’,

},

});

console.log(await response.json());


  • New Participant
  • 3 replies
  • February 4, 2021
Jonathan_Gaunt wrote:

@Taylor_Savage can you point me in the right direction? If I used this code in an automation block, how would I rewrite it to use in an app scripting block? Thanks


let response = await fetch(‘https://api.companieshouse.gov.uk/company/’ + {COMPANY_NUMBER}, {

method: ‘GET’,

headers: {

‘Authorization’ : {API_KEY},

‘Content-Type’: ‘application/json’,

},

});

console.log(await response.json());


Hey @Jonathan_Gaunt ,

If api.companieshouse.gov.uk/company/ supports CORS, you can keep using your code snippet as is. If it doesn’t, I would try replacing fetch with remoteFetchAsync. They take the same arguments, so you shouldn’t need to make any other changes.


  • Author
  • Inspiring
  • 35 replies
  • February 4, 2021
Bill_French wrote:


The follow redirect mode is not supported. Only error and manual are supported. As manual returns an ‘opaque’ response in order to respect atomic HTTP redirect handling, it’s effectively impossible to follow redirects at present.



Sorry, second question - doesn’t this rule out using remote fetch with the entirety of Google APIs since redirection is a fundamental security aspect of Google Cloud Platform and many other API platforms?


By redirects, are you referring to OAuth redirects?


The scripting app isn’t really designed to be able to Auth into secured API’s this way (with no secure place to store things like tokens). This feature is more directly for at least being able to access open endpoints that don’t support CORS.


We are separately considering additional under-the-hood features that would allow a user to separately auth into 3P services, and then let things like the scripting app make requests that take advantage of those stored credentials (without providing direct access to the keys themselves).


  • Inspiring
  • 3264 replies
  • February 4, 2021
Taylor_Savage wrote:

By redirects, are you referring to OAuth redirects?


The scripting app isn’t really designed to be able to Auth into secured API’s this way (with no secure place to store things like tokens). This feature is more directly for at least being able to access open endpoints that don’t support CORS.


We are separately considering additional under-the-hood features that would allow a user to separately auth into 3P services, and then let things like the scripting app make requests that take advantage of those stored credentials (without providing direct access to the keys themselves).



No. As per the gotcha’s…


The follow redirect mode is not supported.


  • Author
  • Inspiring
  • 35 replies
  • February 4, 2021
Bill_French wrote:

No. As per the gotcha’s…


The follow redirect mode is not supported.


Yes it’s correct, follow redirect is not currently supported.


Do you have an example of a Google API that requires redirect that’s not an OAuth redirect? For example, the following code works (and doesn’t actually require remote fetch):


const API_KEY = "$MY_GOOGLE_API_KEY";

const GEOCODE_BASE_URL = "https://maps.googleapis.com/maps/api/geocode/json";



const address = '1600 Pennsylvania Avenue NW Washington, D.C. 20500'



const results = await remoteFetchAsync(GEOCODE_BASE_URL+`?address=${address}&key=${API_KEY}`)



const data = await results.json()



console.log(data);


  • Inspiring
  • 3264 replies
  • February 4, 2021
Taylor_Savage wrote:

Yes it’s correct, follow redirect is not currently supported.


Do you have an example of a Google API that requires redirect that’s not an OAuth redirect? For example, the following code works (and doesn’t actually require remote fetch):


const API_KEY = "$MY_GOOGLE_API_KEY";

const GEOCODE_BASE_URL = "https://maps.googleapis.com/maps/api/geocode/json";



const address = '1600 Pennsylvania Avenue NW Washington, D.C. 20500'



const results = await remoteFetchAsync(GEOCODE_BASE_URL+`?address=${address}&key=${API_KEY}`)



const data = await results.json()



console.log(data);



Sure. This.


What you’ve referenced is a specific Google Maps API that may (or may not) be used with oAuth.


Imagine, however, you wanted to create a webhook service in Google Apps Script using doPost() or doGet(). The resulting endpoint could be easily called by fetch, except that without followRedirects set to true, it won’t work because this is the only behavior Google Cloud Platform supports.



When testing HTTP requests in Google Script with utilities like CURL or Postman, ensure that that “Automatically follow redirects Follow HTTP 3xx responses as redirects” setting is turned on since the ContentService serves a 301 redirect from the script.googleusercontent.com domain.https://www.labnol.org/code/19871-get-post-requests-google-script



I’m simply making the observation that while a CORS remedy is certainly ideal; it is not useful in a variety of platforms that seem to employ this technique for added security.


UPDATE: BTW, @Taylor_Savage - there are two other very recent threads related to this issue here and here that are worth reading.


  • Author
  • Inspiring
  • 35 replies
  • February 5, 2021
Bill_French wrote:

Sure. This.


What you’ve referenced is a specific Google Maps API that may (or may not) be used with oAuth.


Imagine, however, you wanted to create a webhook service in Google Apps Script using doPost() or doGet(). The resulting endpoint could be easily called by fetch, except that without followRedirects set to true, it won’t work because this is the only behavior Google Cloud Platform supports.



When testing HTTP requests in Google Script with utilities like CURL or Postman, ensure that that “Automatically follow redirects Follow HTTP 3xx responses as redirects” setting is turned on since the ContentService serves a 301 redirect from the script.googleusercontent.com domain.https://www.labnol.org/code/19871-get-post-requests-google-script



I’m simply making the observation that while a CORS remedy is certainly ideal; it is not useful in a variety of platforms that seem to employ this technique for added security.


UPDATE: BTW, @Taylor_Savage - there are two other very recent threads related to this issue here and here that are worth reading.


Got it, really interesting, thank you.


Playing a bit of catch-up here - it looks to me like these examples are using Google Apps Script to do some additional scripting-style work outside of the constraints of the Airtable Scripting App itself. Very curious - why specifically Google Apps Scripts? Is it that it’s the simplest environment to write script-style code that’s a) accessible via a public URL endpoint and b) has a lot of flexibility in terms of what you can actually do within the environment? Or that it can easily interface with other Google products? Or something else?


  • Inspiring
  • 3264 replies
  • February 5, 2021
Taylor_Savage wrote:

Got it, really interesting, thank you.


Playing a bit of catch-up here - it looks to me like these examples are using Google Apps Script to do some additional scripting-style work outside of the constraints of the Airtable Scripting App itself. Very curious - why specifically Google Apps Scripts? Is it that it’s the simplest environment to write script-style code that’s a) accessible via a public URL endpoint and b) has a lot of flexibility in terms of what you can actually do within the environment? Or that it can easily interface with other Google products? Or something else?



Um…



  • Free

  • Reliable

  • Agile

  • Pervasively used by 100 million business worldwide

  • Almost every Airtable customer is on Workspaces

  • Consistent javascript client-side and server-side

  • Seamless support for 85 SDKs in the Google ecosystem

  • Native interface to Maps, Drive, Documents, Sheets, Search

  • Seamless pathways to data at scale (Firebase, Big Data, etc.)



Yes, yes, yes, and yes - and many something else’s.


And now there’s Google Tables (an early attempt to create a no-code database veneer).


  • New Participant
  • 1 reply
  • February 9, 2021

Thank you! I am trying to implement the remoteFetchAsync function to call a POST API. I haven’t had any luck yet and I’m not sure if I’m doing it correctly. Do you happen to be free to join a screenshare this week?


Thanks again!


Joe


Awesome @Taylor_Savage! What a great feature.


Curious - is similar functionality coming to Apps (aka Blocks)? I’ve had to work around some CORS issues there as well.


Hi @Taylor_Savage I was able to get remoteFetchAsync in my trigger script but when I try using it as part of an Automation Script it’s telling me that “remoteFetchAsync” is not defined. I can’t use “fetch” due to the CORS issues. Thanks for your help.


  • Author
  • Inspiring
  • 35 replies
  • February 19, 2021
David_Brownman wrote:

Awesome @Taylor_Savage! What a great feature.


Curious - is similar functionality coming to Apps (aka Blocks)? I’ve had to work around some CORS issues there as well.


Hey David! We’re definitely considering a similar functionality with Blocks - just a matter of prioritization on our end.


  • Author
  • Inspiring
  • 35 replies
  • February 19, 2021
Carlos_Cardona wrote:

Hi @Taylor_Savage I was able to get remoteFetchAsync in my trigger script but when I try using it as part of an Automation Script it’s telling me that “remoteFetchAsync” is not defined. I can’t use “fetch” due to the CORS issues. Thanks for your help.


Hey Carlos! Automation Scripts already run in the backend, rather than in a user’s browser, so you shouldn’t run into CORS issues in Automation Scripts (and so don’t need remoteFetchAsync). Maybe something else is causing the fetch to fail?


Taylor_Savage wrote:

Hey Carlos! Automation Scripts already run in the backend, rather than in a user’s browser, so you shouldn’t run into CORS issues in Automation Scripts (and so don’t need remoteFetchAsync). Maybe something else is causing the fetch to fail?


Got fetch to work in Automatons. thanks.


  • Participating Frequently
  • 6 replies
  • October 29, 2021
Bill_French wrote:

Um…



  • Free

  • Reliable

  • Agile

  • Pervasively used by 100 million business worldwide

  • Almost every Airtable customer is on Workspaces

  • Consistent javascript client-side and server-side

  • Seamless support for 85 SDKs in the Google ecosystem

  • Native interface to Maps, Drive, Documents, Sheets, Search

  • Seamless pathways to data at scale (Firebase, Big Data, etc.)



Yes, yes, yes, and yes - and many something else’s.


And now there’s Google Tables (an early attempt to create a no-code database veneer).


Hey @Bill.French, I completely agree with you here. Do you know if there has been any update in this front? I’m trying to call a GAS webhook and having a real hard time with both fetch and remoteFetchAsync.


Any successful examples you’ve seen out there?


  • Inspiring
  • 3264 replies
  • October 29, 2021
Sebastian_Muril wrote:

Hey @Bill.French, I completely agree with you here. Do you know if there has been any update in this front? I’m trying to call a GAS webhook and having a real hard time with both fetch and remoteFetchAsync.


Any successful examples you’ve seen out there?


No changes from Airtable that I know of, but this pattern seems to work well with Google Apps Script hosted webhooks. The issue, of course, is that I believe the response from the webhook service is sent but not detected by Airtable.


// get the location for this order

let gWebhookURL = "https://script.google.com/macros/s/AKfycbyvaERhqYfV1U14GjzSfeg_MeR2GawIzbImok4HlCH2JAp7tg/exec?token=gff67yt290&task=build-additionalpayment-document&id=" + thisID;



// call the webhook service

try {

  await fetch(gWebhookURL, {method: 'get', mode: 'no-cors', redirect: 'manual'})

  // the response will be a web page redirect that Airtable cannot follow

} catch (e) {

  // do nothing... (airtable doesn't support follow redirects so this should fail every time unless redirect:manual is passed)

  console.log("FETCH: " + e.message);

  console.log('FAILED!');

}


  • Participating Frequently
  • 6 replies
  • October 29, 2021

Ahh, I see. I’m getting a “Failed to fetch”… Would this be enough to trigger the script in GAS? If so, I can have the script in GAS pull the data from Airtable and keep the UI all in Airtable. Maybe that could be a workaround, what do you think?


Also, is thisID for the Deployment ID in GAS?


Thanks for your help.





  • Participating Frequently
  • 6 replies
  • October 29, 2021
Sebastian_Muril wrote:

Ahh, I see. I’m getting a “Failed to fetch”… Would this be enough to trigger the script in GAS? If so, I can have the script in GAS pull the data from Airtable and keep the UI all in Airtable. Maybe that could be a workaround, what do you think?


Also, is thisID for the Deployment ID in GAS?


Thanks for your help.





Or maybe even an Integromat webhook could do the trick? And from there I can trigger the GAS script. But not sure if this is possible from the Script App either.


  • Inspiring
  • 3264 replies
  • October 31, 2021
Sebastian_Muril wrote:

Ahh, I see. I’m getting a “Failed to fetch”… Would this be enough to trigger the script in GAS? If so, I can have the script in GAS pull the data from Airtable and keep the UI all in Airtable. Maybe that could be a workaround, what do you think?


Also, is thisID for the Deployment ID in GAS?


Thanks for your help.






Yes. That’s precisely how it is used in this case.



Yep - I do this all the time.



It’s the endpoint of a webservice deployed in Google Cloud using Google Apps Script.


  • Participating Frequently
  • 6 replies
  • November 1, 2021

Hey Bill, I’m trying to put together the endpoint but not sure I’m in the right path. Is this the right logic?


The gWebhook URL is made up of: Web App URL + “?token=gff67yt290&task=build-additionalpayment-document&id=” (where does this come from?) + Endpoint of webservice deployed in Google Cloud (am I in the right place in the Cloud console to get this ID from?)


Where:


Web App URL:



Endpoint of webservice deployed in Google Cloud:



Thanks again for your help or any docs that you think can point me in the right direction 🙏 .


  • Inspiring
  • 3264 replies
  • November 1, 2021
Sebastian_Muril wrote:

Hey Bill, I’m trying to put together the endpoint but not sure I’m in the right path. Is this the right logic?


The gWebhook URL is made up of: Web App URL + “?token=gff67yt290&task=build-additionalpayment-document&id=” (where does this come from?) + Endpoint of webservice deployed in Google Cloud (am I in the right place in the Cloud console to get this ID from?)


Where:


Web App URL:



Endpoint of webservice deployed in Google Cloud:



Thanks again for your help or any docs that you think can point me in the right direction 🙏 .



Google makes these URLs and because of this, they are somewhat secure. You must deploy a web app to get a working URL for that web service.


Taylor_Savage wrote:

Hey David! We’re definitely considering a similar functionality with Blocks - just a matter of prioritization on our end.


Hey Taylor! Just wanted to check in here- is bringing the server-side fetch functionality still planned for Extensions (previously Blocks)? It would be super useful, personally!


Reply