Retrieving information from a public Google spreadsheet using client-side JavaScript

How can I retrieve cell values from a public Google spreadsheet?

GET https://sheets.googleapis.com/v4/spreadsheets/1vW01Y46DcpCC7aKLIUwV_W4RXLbeukVwF-G9AA7P7R0/values/A1A4?key=abcdef

The above request returns a 403 error.

I also included the Referrer in Postman :

Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36

{
    "error": {
        "code": 403,
        "message": "Requests from referer Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36 are blocked.",
        "status": "PERMISSION_DENIED",
        "details": [
            {
                "@type": "type.googleapis.com/google.rpc.ErrorInfo",
                "reason": "API_KEY_HTTP_REFERRER_BLOCKED",
                "domain": "googleapis.com",
                "metadata": {
                    "consumer": "projects/666",
                    "service": "sheets.googleapis.com"
                }
            }
        ]
    }
}

I am attempting to access data directly from a public sheet using client-side JavaScript.

No need for server round-trips. I vaguely remember this being possible around 10 years ago but I can't find the documentation now.

Answer №1

Gain access to the public spreadsheet through a JSON endpoint

var id = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
var gid = '1111111111111';
var url = 'https://docs.google.com/spreadsheets/d/'+id+'/gviz/tq?tqx=out:json&tq&gid='+gid;

Grab a portion of the data

data.substring(47).slice(0, -2)

Then, decode the JSON information

Shortcut link

https://docs.google.com/spreadsheets/d/1n-rjSYb63Z2jySS3-M0BQ78vu8DTPOjG-SZM4i8IxXI/gviz/tq?tqx=out:json&tq&gid=0

Sample using Google Apps Script

function getEndpointJson(){
  var id = '1n-rjSYb63Z2jySS3-M0BQ78vu8DTPOjG-SZM4i8IxXI';
  var gid = '0';
  var txt = UrlFetchApp.fetch(`https://docs.google.com/spreadsheets/d/${id}/gviz/tq?tqx=out:json&tq&gid=${gid}`).getContentText();
  var jsonString = txt.match(/(?<="table":).*(?=}\);)/g)[0]
  var json = JSON.parse(jsonString)
  var table = []
  var row = []
  json.cols.forEach(col => row.push(col.label))
  table.push(row)
  json.rows.forEach(r => {
    var row = []
    r.c.forEach(cel => {
        try{var value = cel.f ? cel.f : cel.v}
        catch(e){var value = ''}
        row.push(value)
      }
    )
    table.push(row)
    }
  )
  return (table)
}

Demonstration on an HTML page

For example, on an HTML page hosted externally

<html>
<title>Google Sheets JSON Endpoint V4</title>
<author>Mike Steelson</author>
<style>
table {border-collapse: collapse;}
th,td{border: 1px solid black;}
</style>
<body>
<div id="json">json here</div>
<script>
var id = '1n-rjSYb63Z2jySS3-M0BQ78vu8DTPOjG-SZM4i8IxXI';
var gid = '0';
var url = 'https://docs.google.com/spreadsheets/d/'+id+'/gviz/tq?tqx=out:json&tq&gid='+gid;
fetch(url)
  .then(response => response.text())
  .then(data => document.getElementById("json").innerHTML=myItems(data.substring(47).slice(0, -2))  
  );
function myItems(jsonString){
  var json = JSON.parse(jsonString);
  var table = '<table><tr>'
  json.table.cols.forEach(col => table += '<th>' + col.label + '</th>')
  table += '</tr>'
  json.table.rows.forEach(row => {
    table += '<tr>'
    row.c.forEach(cell => {
        try{var value = cell.f ? cell.f : cell.v}
        catch(e){var value = ''}
        table += '<td>' + value + '</td>'
      }
    )
    table += '</tr>'
    }
  )
  table += '</table>'
  return table
}           
</script>
</body></html>

The sheet ID provided is incorrect.

Answer №2

After conducting a quick review, it appears that there are readily available JS libraries that allow access to GSheets data, however, Google mandates the use of API keys:

When accessing public data through the Google Sheets API, an identifier such as an API key or access token is required.

One example of such a library is:

gsheets - A tool to retrieve public Google Sheets information in plain JavaScript/JSON format.

Answer №4

Here's a helpful library you may want to consider.

Check out this library for public Google Sheets parsing

You can utilize it in the following manner:

const PublicGoogleSheetsParser = require('public-google-sheets-parser')

const spreadsheetId = '10WDbAPAY7Xl5DT36VuMheTPTTpqx9x0C5sDCnh4BGps'

// 1. Instantiating the parser with the spreadsheetId:
const parser = new PublicGoogleSheetsParser(spreadsheetId)
parser.parse().then((items) => {
  // items will contain data objects like: [{"a":1,"b":2,"c":3},{"a":4,"b":5,"c":6},{"a":7,"b":8,"c":9}]
})

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Locate the index position of an element in one array based on a corresponding element in a

I am seeking a way to determine the index and group that an item belongs to within a parent json group. Is there a method for achieving this? I am willing to modify the json format if necessary. I made an attempt using JSON.stringify(), but it seems to be ...

Pass a JavaScript variable to a PHP script using AJAX when a button is clicked, with a dynamically set href attribute

This is the current situation: There is a checkbox on each row of a table that represents some information An initially disabled button becomes enabled when any checkbox is checked The button is enclosed by an <a></a> tag as shown: <a>&l ...

The async/await syntax can be finicky at times and may not always

Using Vue, I want to implement async/await to sequence my functions A and B. Result is set to false by default. mounted() { this.A(); this.B(); } async A() { this.result = await this.$api... } async B() { if(this.result) { let data = awa ...

Steps to sending a parameter to an AngularJS $http success callback

In my AngularJS application, I have implemented the following code: $http.get('/plugin/' + key + '/js').success(function (data) { if (data.length > 0) { console.log(data); // Here, I also need to retrieve the val ...

Allow editing for only a specific part of a text box

Creating a customized personal URL page for users on my site is important to me. I envision the value of a text box being "example.com/username," with the "example.com/" part displayed in the text box, but not editable. I've noticed that Tumblr accom ...

What is the best way to execute JavaScript on the main MVC page when an AJAX request in a partial view has finished?

My Asp.net MVC partial view is designed for searching and makes an Ajax call to retrieve results. After the results are displayed, the user can select a search result by clicking on a link in one of the rows. Upon selecting a search result, an Ajax post re ...

What is the best way to populate a remote html page in real-time according to user input?

Is it feasible to use only JavaScript and HTML to allow users to select from a list of options and then print a page that includes a checklist of their selections? ...

Steps for embedding JavaScript code within HTML tags using a JavaScript file

Working on a React web app, I am solely using js and css files without any html. In one of my js files, there is a mix of html and js code like this: class Teams extends Component { state = { teams: [] } componentDidMount() { ...

Is there a way for me to connect the ajax data to Vue components?

Utilizing Jquery ajax to load data from an external API has been successful and the v-for text is also working without any issues. Vue var vm = new Vue({ el:'.inlinePoetry', data:{ PoetryList:[] }, created:function(){ var ...

I am in search of a specialized 3D camera with a unique effect

I am seeking assistance with animating a camera to replicate or closely resemble the effect seen in this demo: Any help would be greatly appreciated. ...

Ways to verify if JSON response is null using jquery

$.getJSON(url, function(json) { var output = ''; $.each(json, function(i,d) { if(d.DESCRIPTION == 'null'){ console.log("Its empty"); } var description = d.DESCRIPTION; output += '<tr><td>&apo ...

Angular debounce on checkboxes allows you to prevent multiple rapid changes from

Managing multiple checkboxes to filter a dataset can be tricky. I am looking for a way to debounce the checkbox selection so that the filter is only triggered after a certain period of time, like waiting 500ms to a second after the last checkbox has been c ...

Utilizing HTML5 canvas to extract pixel data from an image loaded from an external source

When it comes to security reasons, doing it directly may not be feasible. Nevertheless, there are rumors circulating about certain image-hosting platforms that permit the use of their images in a comparable way (could Google Picasa be one?). I might be mis ...

Converting a React element using JSON.stringify results in transforming it into a JavaScript object

I have an element in React called testReactElement that I want to display on the screen. I also want it to persist even after the user closes the tab and opens it again, so I decided to store it in localStorage. To add a React element to localStorage, I fi ...

Identifying line breaks caused by browsers or CSS forced line breaks

<p style="width:60px"> This is just a sample text. It is a piece of text that doesn't really say anything meaningful.</p> When this text is rendered as HTML, it would look like this: This is just a sample text. It is a piece of text ...

Determine whether any property within the object is currently null

I am working with an array of objects called data, each object in the array having multiple properties, some of which may have null values. https://i.sstatic.net/hc5O3.png My goal is to filter through this array and eliminate any object that contains a p ...

Toggle visibility with jQuery's Show & Hide feature

Currently, I am working with some divs that need to be hidden (with the class .hideable) and others that need to be shown (with the class .toggleable). I have made progress in getting everything to work as desired. However, I am facing a challenge - once t ...

In AngularJS, showcasing five elements at a time from an array containing 'n' items before looping back to the beginning

I'm a beginner in AngularJS and facing a scenario where I need to display 5 items from an array containing multiple items. The requirement is to initially show items 1-5 and then, after 2-3 seconds, add a 6th item at the top and remove the last item f ...

Jquery: Pressing Enter will cause the input field to lose

Take a look at this fiddle I created: http://jsfiddle.net/7wp9rs2s/. This is the progress I have made on my project so far. In the fiddle above, you can double click on one of the 4 items and a textbox will appear for editing. Instead of clicking out of t ...

AngularJS Large file size

After successfully building the 5 MIN QUICKSTART app, I decided to minify it with webpack following the recommendations in the angularJS docs. To my surprise, the size of the minified AngularJS file turned out to be approximately 700 KB, which is significa ...