---
title: Google Sheets
pagination_prev: demos/static/index
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
This demo uses `node-google-spreadsheet` to interact with Google Sheets v4 API.
:::caution
Google Sheets deprecates APIs quickly and there is no guarantee that the
referenced API version will be available in the future.
:::
## Initial Configuration
Install the dependencies:
```bash
npm i https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz google-spreadsheet@3.3.0
```
The library README has a [guide](https://theoephraim.github.io/node-google-spreadsheet/#/getting-started/authentication)
for configuring a service worker with write access to the document.  Following
the service worker guide, the JSON key should be saved to `key.json`.
The following helper function attempts to authenticate and access the specified
sheet by ID.  The code should be copied and saved to `common.js`:
Code (click to show)
```js title=common.js
const fs = require("fs");
const { GoogleSpreadsheet } = require('google-spreadsheet');
module.exports = async(ID) => {
  /* get credentials */
  const creds = JSON.parse(fs.readFileSync('key.json'));
  /* initialize sheet and authenticate */
  const doc = new GoogleSpreadsheet(ID);
  await doc.useServiceAccountAuth(creds);
  await doc.loadInfo();
  return doc;
}
```
How to run locally (click to show)
0) Follow the [Initial Configuration](#initial-configuration).
1) Create a new Google Sheet and share with the generated service account.  It
should be granted the "Editor" role
2) Install the dependencies:
```
npm i https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz google-spreadsheet@3.3.0
```
2) Save the following snippet to `common.js`:
```js title=common.js
const fs = require("fs");
const { GoogleSpreadsheet } = require('google-spreadsheet');
module.exports = async(ID) => {
  /* get credentials */
  const creds = JSON.parse(fs.readFileSync('key.json'));
  /* initialize sheet and authenticate */
  const doc = new GoogleSpreadsheet(ID);
  await doc.useServiceAccountAuth(creds);
  await doc.loadInfo();
  return doc;
}
```
3) Save the following snippet to `pull.js`:
```js title=pull.js
const XLSX = require("xlsx");
/* create a blank workbook */
const wb = XLSX.utils.book_new();
const init = require("./common");
const ID = "";
(async() => {
  const doc = await init(ID);
  for(let i = 0; i < doc.sheetsByIndex.length; ++i) {
    const sheet = doc.sheetsByIndex[i];
    const name = sheet.title;
    /* get the header and data rows */
    await sheet.loadHeaderRow();
    const header = sheet.headerValues;
    const rows = await sheet.getRows();
    const aoa = [header].concat(rows.map(r => r._rawData));
    /* generate a SheetJS Worksheet */
    const ws = XLSX.utils.aoa_to_sheet(aoa);
    /* add to workbook */
    XLSX.utils.book_append_sheet(wb, ws, name);
  }
  /* write to SheetJS.xlsb */
  XLSX.writeFile(wb, "SheetJS.xlsb");
})();
```
4) Replace `` with the ID of the actual document.
5) Run `node pull.js` once. It will create `SheetJS.xlsb`.
6) Open `SheetJS.xlsb` and confirm the contents are the same as Google Sheets.
7) Change some cells in the Google Sheets Document.
8) Run `node pull.js` again and reopen `SheetJS.xlsb` to confirm value changes.
How to run locally (click to show)
0) Follow the [Initial Configuration](#initial-configuration).
1) Create a new Google Sheet and share with the generated service account.  It
should be granted the "Editor" role
2) Install the dependencies:
```
npm i https://cdn.sheetjs.com/xlsx-latest/xlsx-latest.tgz google-spreadsheet@3.3.0
```
2) Save the following snippet to `common.js`:
```js title=common.js
const fs = require("fs");
const { GoogleSpreadsheet } = require('google-spreadsheet');
module.exports = async(ID) => {
  /* get credentials */
  const creds = JSON.parse(fs.readFileSync('key.json'));
  /* initialize sheet and authenticate */
  const doc = new GoogleSpreadsheet(ID);
  await doc.useServiceAccountAuth(creds);
  await doc.loadInfo();
  return doc;
}
```
3) Save the following snippet to `push.js`:
```js title=push.js
const XLSX = require("xlsx");
const fs = require("fs");
/* create dummy worksheet if `sheetjs.xlsx` does not exist */
if(!fs.existsSync("sheetjs.xlsx")) {
  const wb = XLSX.utils.book_new();
  const ws1 = XLSX.utils.aoa_to_sheet([["a","b","c"],[1,2,3]]); XLSX.utils.book_append_sheet(wb, ws1, "Sheet1");
  const ws2 = XLSX.utils.aoa_to_sheet([["a","b","c"],[4,5,6]]); XLSX.utils.book_append_sheet(wb, ws2, "Sheet2");
  XLSX.writeFile(wb, "sheetjs.xlsx");
}
/* read and parse sheetjs.xlsx */
const wb = XLSX.readFile("sheetjs.xlsx");
const init = require("./common");
const ID = "";
(async() => {
  const doc = await init(ID);
  /* clear workbook */
  {
    /* delete all sheets after the first sheet */
    const old_sheets = doc.sheetsByIndex;
    for(let i = 1; i < old_sheets.length; ++i) {
      await old_sheets[i].delete();
    }
    /* clear first worksheet */
    old_sheets[0].clear();
  }
  /* write worksheets */
  {
    const name = wb.SheetNames[0];
    const ws = wb.Sheets[name];
    /* first worksheet already exists */
    const sheet = doc.sheetsByIndex[0];
    /* update worksheet name */
    await sheet.updateProperties({title: name});
    /* generate array of arrays from the first worksheet */
    const aoa = XLSX.utils.sheet_to_json(ws, {header: 1});
    /* set document header row to first row of the AOA */
    await sheet.setHeaderRow(aoa[0])
    /* add the remaining rows */
    await sheet.addRows(aoa.slice(1));
    /* the other worksheets must be created manually */
    for(let i = 1; i < wb.SheetNames.length; ++i) {
      const name = wb.SheetNames[i];
      const ws = wb.Sheets[name];
      const sheet = await doc.addSheet({title: name});
      const aoa = XLSX.utils.sheet_to_json(ws, {header: 1});
      await sheet.setHeaderRow(aoa[0])
      await sheet.addRows(aoa.slice(1));
    }
  }
})();
```
4) Replace `` with the ID of the actual document.
5) Run `node push.js` once. It will create `sheetjs.xlsx` and update the sheet.
6) Edit `sheetjs.xlsx` with some new data
7) Run `node push.js` again and watch the Google Sheet update!