QuotaGuard and Google Apps Script Integration Guide

QuotaGuard and Google Apps Script Integration Guide

Google Apps Script runs your UrlFetchApp.fetch() calls from Google’s shared infrastructure, so the source IP a partner API sees is not fixed and cannot be allowlisted. This guide gives those calls two static IP addresses. You deploy a small relay function that egresses through QuotaGuard, then point your script at the relay with two headers. Every request then exits from one of the two static IPs assigned to your QuotaGuard subscription.

Get two static IPs for Google Apps Script

Google Apps Script has no HTTP proxy setting. The UrlFetchApp.fetch(url, params) options object exposes method, headers, payload, contentType, muteHttpExceptions, followRedirects, timeoutSeconds, and a few others, but no proxy field. The sandbox also has no environment variables and no sidecar process, so the usual QUOTAGUARDSTATIC_URL and QGTunnel approaches do not apply here.

The fix is a relay. You host a small function (an AWS Lambda or a Google Cloud Function) that itself egresses through QuotaGuard Static. Your Apps Script calls that relay’s URL and passes the real target API in a header. The relay forwards the request through QuotaGuard, and the target API sees one of your two static IPs. This is the standard pattern for any platform that cannot set an HTTP proxy, documented in full at Static IPs when you cannot set an HTTP proxy.

Why Google Apps Script needs a static IP

Apps Script fetches leave from Google’s shared egress ranges. Those addresses rotate and are shared across many Google customers, so you cannot hand a partner a stable IP to allowlist, and you would never want to allowlist Google’s entire range. Any destination that gates access by source IP will either reject your script or force you to leave the gate wide open.

Common destinations that require a fixed, allowlistable source IP:

  • Payment gateways and financial APIs that require IP allowlisting
  • Partner and supplier APIs behind a firewall allowlist
  • MongoDB Atlas, Supabase, Neon, and Amazon RDS access lists
  • Legacy or on-prem systems reachable only from known IPs
  • Internal enterprise APIs that enforce a source-IP policy
  • Any vendor that issues credentials scoped to a registered IP

With QuotaGuard, you allowlist exactly the two static IPs shown in your dashboard, in both directions, and your Apps Script traffic arrives from a stable, known source.

Set up the relay

The relay is a small function you own that forwards a request through QuotaGuard Static and returns the response. It reads two headers from the incoming request:

  • X-Relay-Key: a shared secret you set, so only your script can use the relay
  • X-Target-URL: the real API URL you want to reach

It forwards the request through the QUOTAGUARDSTATIC_URL connection in its own environment, so the target API sees your two static IPs.

You do not need to write this from scratch. Use the ready-to-run example and the reusable pattern doc:

Deploy the relay, set its QUOTAGUARDSTATIC_URL to the value from your QuotaGuard dashboard, set a strong X-Relay-Key secret, and note the deployed function URL. The rest of this guide is the Google Apps Script side.

Call the relay from Google Apps Script

Point UrlFetchApp.fetch() at your relay URL and pass the two headers. The X-Target-URL header carries the API you actually want to reach.

function callThroughRelay() {
  var props = PropertiesService.getScriptProperties();
  var RELAY_URL = props.getProperty('RELAY_URL');
  var RELAY_KEY = props.getProperty('RELAY_KEY');

  var response = UrlFetchApp.fetch(RELAY_URL, {
    method: 'get',
    headers: {
      'X-Relay-Key': RELAY_KEY,
      'X-Target-URL': 'https://api.partner.com/v1/orders'
    },
    muteHttpExceptions: true
  });

  Logger.log(response.getResponseCode());
  Logger.log(response.getContentText());
}

Store the relay URL and key in Script Properties (Project Settings > Script Properties), not inline in your code. PropertiesService.getScriptProperties() reads them at runtime and keeps the secret out of your source.

For a POST that sends a JSON body to the target API, pass the body as payload and set the content type. The relay forwards the method, headers, and body to the X-Target-URL:

function postThroughRelay() {
  var props = PropertiesService.getScriptProperties();
  var RELAY_URL = props.getProperty('RELAY_URL');
  var RELAY_KEY = props.getProperty('RELAY_KEY');

  var body = {
    reference: 'INV-2043',
    amount: 4999
  };

  var response = UrlFetchApp.fetch(RELAY_URL, {
    method: 'post',
    contentType: 'application/json',
    headers: {
      'X-Relay-Key': RELAY_KEY,
      'X-Target-URL': 'https://api.partner.com/v1/charges'
    },
    payload: JSON.stringify(body),
    muteHttpExceptions: true
  });

  Logger.log(response.getResponseCode());
  Logger.log(response.getContentText());
}

If the target API needs its own auth header (a bearer token or API key), add it to the headers map alongside the two relay headers. The example relay forwards the Content-Type and Authorization headers to the target. If the target needs a different custom header (for example X-Api-Key), add that header name to the forwarding list in the relay function.

Test that traffic exits from your static IPs

QuotaGuard runs an IP check endpoint at https://ip.quotaguard.com that returns the source IP it saw. Point X-Target-URL at it and read the response.

function testStaticIp() {
  var props = PropertiesService.getScriptProperties();
  var response = UrlFetchApp.fetch(props.getProperty('RELAY_URL'), {
    method: 'get',
    headers: {
      'X-Relay-Key': props.getProperty('RELAY_KEY'),
      'X-Target-URL': 'https://ip.quotaguard.com'
    },
    muteHttpExceptions: true
  });
  Logger.log(response.getContentText());
}

Expected response:

{"ip":"<one of your two QuotaGuard static IPs>"}

The returned IP must match one of the two static IPs in your QuotaGuard dashboard. Run the function a few times. Because the two IPs are load balanced, repeated calls will show both addresses. Allowlist both on every destination that gates by IP.

Troubleshooting

403 or “invalid relay key” from the relay. The X-Relay-Key your script sends does not match the secret configured on the relay. Confirm the value in Script Properties matches the relay’s environment exactly, with no trailing whitespace. Rotate the secret on both sides if you are unsure.

Returned IP is a Google address, not a QuotaGuard IP. The request reached the target directly instead of going through the relay. Check that RELAY_URL points at your deployed relay and not at the target API, and that the relay itself has QUOTAGUARDSTATIC_URL set. A relay with no QuotaGuard connection egresses from its own host IP.

The target still rejects the request after you see a QuotaGuard IP. Only one of the two static IPs has been allowlisted on the destination. Add both IPs from your dashboard. The load balancer will use either one.

Address unavailable or a timeout from UrlFetchApp.fetch(). The relay URL is unreachable or slow. Verify the function is deployed and reachable from Apps Script. Apps Script waits up to the timeoutSeconds value (default 360). Set a lower timeoutSeconds if you want faster failures during testing.

Exception: Request failed ... returned code 502 or 504. The relay reached QuotaGuard but the upstream target errored or timed out. Add muteHttpExceptions: true and log getResponseCode() and getContentText() to see the body the relay returned, then check the relay’s own logs.

Secret not loading at runtime. PropertiesService.getScriptProperties().getProperty(...) returns null when the property name does not exist. Property names are case sensitive. Confirm the keys in Project Settings > Script Properties match the strings in your code.

QuotaGuard Static vs QuotaGuard Shield

Static is the right product for standard HTTPS API calls from Google Apps Script. The HTTPS payload is tunneled end to end and is never decrypted at the proxy. Choose Shield only when the workload handles regulated data (HIPAA, PCI-DSS, SOC 2) or the environment requires TLS on every hop between your relay and the proxy.

Feature QuotaGuard Static QuotaGuard Shield
Protocol HTTP / HTTPS / SOCKS5 HTTPS / SOCKS5 over TLS
Customer-to-proxy hop Plaintext TLS-encrypted
HTTPS payload Tunneled end-to-end, never decrypted at the proxy Tunneled end-to-end, never decrypted at the proxy
Best for Most apps Regulated data or environments that require TLS on every hop
Starting price $19/month (direct) $29/month (direct)

Static is right for most Google Apps Script integrations. Choose Shield if the workload handles regulated data or the environment requires TLS between your relay and the proxy itself.

Ready to Get Started?

Get in touch or create a free trial account.

Try QuotaGuard Now

Read: Static IPs when you cannot set an HTTP proxy

Contact Support


Ready to Get Started?

Get in touch or create a free trial account

Back to top ↑

Copyright © 2009 - 2026 QuotaGuard. All rights reserved.

Copyright © 2009 - 2026 QuotaGuard. All rights reserved.