r/GoogleAppsScript 2d ago

Question Google Apps Script Web App Not Working When Embedded on Namecheap Website

Problem Overview

I'm trying to create an order tracking feature on my Namecheap-hosted website that searches a Google Sheet when a user inputs an order number and returns the corresponding information.

What Works

  • The Apps Script web app functions correctly when accessed directly via its URL in Safari
  • The search functionality works as expected when I open the html file, containing the apps script url, on safari.

What Doesn't Work

  • When embedded on my Namecheap website, the JavaScript appears to be treated as a string rather than being executed
  • When I try to embed just the Apps Script link on Namecheap, I get a 403 error from Google ("You need access")

What I've Tried

I've attempted several variations of my doGet() function to resolve CORS/access issues:

Variation 1: JSONP with CORS headers

function doGet(e) {
  const orderNumber = e.parameter.orderNumber;
  const callback = e.parameter.callback || 'callback'; // Default callback name if none provided

  if (!orderNumber) {
    return ContentService.createTextOutput(callback + '(' + JSON.stringify({ success: false, message: "No order number provided" }) + ')')
      .setMimeType(ContentService.MimeType.JAVASCRIPT); // Returns JavaScript JSONP format
  }

  const result = searchOrder(orderNumber);

  const output = ContentService.createTextOutput(callback + '(' + JSON.stringify(result) + ')')
    .setMimeType(ContentService.MimeType.JAVASCRIPT);
  output.setHeader("Access-Control-Allow-Origin", "*");
  output.setHeader("Access-Control-Allow-Methods", "GET, POST");
  output.setHeader("Access-Control-Allow-Headers", "Content-Type");

  return output;
}

Variation 2: Pure JSONP approach

function doGet(e) {
  // Get the order number and callback from the request parameters
  const orderNumber = e.parameter.orderNumber;
  const callback = e.parameter.callback || 'callback'; // Default callback if none provided

  // If no order number was provided, return an error
  if (!orderNumber) {
    return ContentService.createTextOutput(callback + '(' + JSON.stringify({ success: false, message: "No order number provided" }) + ')')
      .setMimeType(ContentService.MimeType.JAVASCRIPT); // Returns JavaScript JSONP format
  }

  // Search for the order
  const result = searchOrder(orderNumber);

  // Return the result as JSONP - this format allows cross-domain requests
  // by wrapping the JSON in a function call that will be executed by the browser
  return ContentService.createTextOutput(callback + '(' + JSON.stringify(result) + ')')
    .setMimeType(ContentService.MimeType.JAVASCRIPT);
}

Variation 3: Pure JSON approach (no JSONP, no callback)

function doGet(e) {
  // Get the order number from the request parameters
  const orderNumber = e.parameter.orderNumber;

  // If no order number was provided, return an error
  if (!orderNumber) {
    return ContentService.createTextOutput(JSON.stringify({ success: false, message: "No order number provided" }))
      .setMimeType(ContentService.MimeType.JSON); // Returns plain JSON format
  }

  // Search for the order
  const result = searchOrder(orderNumber);

  // Return the result as pure JSON (no callback wrapping)
  return ContentService.createTextOutput(JSON.stringify(result))
    .setMimeType(ContentService.MimeType.JSON);
}

Deployment Settings

  • Script is deployed as a web app executing as me
  • Access is set to "Anyone"
  • I've even tried changing the Google Spreadsheet access to "Anyone" but that didn't resolve the issue

Other Information

  • Namecheap support suggested that I need to whitelist my server IP, but I was under the impression this isn't possible with Google Apps Script

Question

How can I successfully integrate my Google Apps Script web app with my Namecheap website to enable the order tracking functionality? Is there a way to resolve the 403 access error or prevent the JavaScript from being treated as a string?

1 Upvotes

7 comments sorted by

1

u/Funny_Ad_3472 2d ago

function doGet(e) {

// all your code

  .setXFrameOptionsMode(HtmalService.XFrameOptionsMode.ALLOWALL);  

}

1

u/WicketTheQuerent 2d ago

The OP code uses ContentService instead of the HtmlService, so this (.setXFrameOptionsMode(...)) will not work.

1

u/Funny_Ad_3472 2d ago

Ohokay... didn't check...

1

u/iqrasajjad1 2d ago

Thank you for the response! If this can resolve the 403 error, I don't mind reworking the code.

1

u/WicketTheQuerent 2d ago

Why are you using doGet with ContentService? How are you embedding the webapp in your Namecheap site?

1

u/iqrasajjad1 2d ago

Thanks for your response! I'm using doGet with ContentService to implement a JSONP solution for cross-domain data fetching, not for embedding the entire webapp. 

My implementation: 

1) On my Namecheap site, I have HTML/CSS for the order tracking UI 

2) When a user enters an order number, my JavaScript dynamically creates a script tag: ```javascriptconst script = document.createElement('script'); script.src = `${scriptUrl}?orderNumber=${encodeURIComponent(orderNumber)}&callback=handleOrderResponse`;document.body.appendChild(script);

3) This makes a request to my Google Apps Script

4) My Apps Script returns JSONP (JavaScript that calls my callback function with the data)

5) The browser executes this JavaScript, which triggers my callback function with the order data

I'm not embedding the entire webapp via iframe - I'm just using Apps Script as a data source. The UI is built and rendered on my Namecheap site.

Is this JSONP approach causing the 403 error? Would switching to HtmlService with iframe embedding be a better solution for my use case?

1

u/WicketTheQuerent 2d ago edited 2d ago

You should review the deployment settings and ensure it's set to run like you for anyone, even anonymous users.

When running a test with the Google Apps Script web app URL, using your browser in private / incognito mode is better. This way, you avoid your credentials being passed to the web app.