Pricing

How to Connect WooCommerce to Google Sheets

WooCommerceSaved SearchDateDocumentAmount07/01INV-40214,280.0007/02INV-40221,860.5007/05INV-40239,140.0007/08INV-40242,375.2507/09INV-40256,902.7507/12INV-40263,118.40BrookedABCDateDocumentAmount123456707/01INV-40214,280.0007/02INV-40221,860.5007/05INV-40239,140.0007/08INV-40242,375.2507/09INV-40256,902.7507/12INV-40263,118.40Google SheetsWooCommerce report
JW
James Whitfield

Sync WooCommerce orders and products to Google Sheets via the REST API, including the permalink setting that 404s the whole API and the hosts that strip your auth header.

WooCommerce has a capable REST API, and connecting it to Sheets is straightforward once two self-hosted quirks are out of the way: the API returns 404 on every route if WordPress permalinks are set to Plain, and many shared hosts strip the Authorization header so valid credentials arrive as 401. This guide covers both, plus pagination, line-item structure, and the free CSV route.

The built-in option: CSV export

WooCommerce ships a product CSV exporter at Products → All Products → Export, which handles the catalogue including custom meta. Orders are the gap: core WooCommerce has no built-in order exporter, so store owners typically add a free plugin for that. Import the resulting file into Sheets via File → Import.

WooCommerce to Google Sheets for free (Apps Script + REST API)

Generate credentials under WooCommerce → Settings → Advanced → REST API → Add key. Choose Read permission for reporting, and copy the consumer key (ck_…) and consumer secret (cs_…) immediately, since the secret is only shown once.

Before writing any code, confirm two things. Under Settings → Permalinks, the structure must not be Plain, or /wp-json/ does not exist at all; set it to Post name and re-save to flush the rewrite rules. And confirm the store is served over HTTPS: WooCommerce accepts basic auth over HTTPS, but over plain HTTP it requires OAuth 1.0a request signing, which is far more work.

Code.gs
function importWooOrders() {  const STORE  = "https://yourstore.com";  const KEY    = "ck_XXXXXXXXXXXX";  const SECRET = "cs_XXXXXXXXXXXX";   // Query-string auth avoids hosts that strip the Authorization header.  // It is acceptable over HTTPS; never do this over plain HTTP.  const auth = "consumer_key=" + KEY + "&consumer_secret=" + SECRET;   const rows = [];  let page = 1;   while (true) {    const url = STORE + "/wp-json/wc/v3/orders"      + "?per_page=100&page=" + page          // 100 is the maximum      + "&after=2026-01-01T00:00:00"          // narrow the window where you can      + "&" + auth;     const response = UrlFetchApp.fetch(url, { muteHttpExceptions: true });    if (response.getResponseCode() !== 200) {      throw new Error(response.getResponseCode() + ": " + response.getContentText());    }     const orders = JSON.parse(response.getContentText());    if (!orders.length) break;     orders.forEach((o) => {      // One row per order, with line items summarised. Writing one row per      // line item instead would repeat the order total and inflate revenue.      rows.push([        o.number,        o.date_created,        o.status,        o.billing.email,        o.total,                                    // string, not a number        o.currency,        o.line_items.map((li) => li.name + " x" + li.quantity).join("; "),        o.line_items.reduce((n, li) => n + li.quantity, 0),      ]);    });     if (orders.length < 100) break;    page++;  }   const header = ["Order","Created","Status","Email","Total","Currency","Items","Units"];  const ss = SpreadsheetApp.getActiveSpreadsheet();  const sheet = ss.getSheetByName("Orders") || ss.insertSheet("Orders");  sheet.clearContents();  sheet.getRange(1, 1, 1, header.length).setValues([header]);  if (rows.length) {    sheet.getRange(2, 1, rows.length, header.length).setValues(rows);  }}

Two details worth noting. WooCommerce returns monetary values as strings, so o.total lands as text and needs coercing before Sheets will sum it. And the decision the code makes explicitly, one row per order with items summarised, is the one that keeps revenue totals correct; flattening to one row per line item repeats the order total on every row.

Limits: Apps Script stops at six minutes, so large stores need chunking with after and before across runs. Paging deep into a big order table also gets slow on modest hosting, since each page is a database query on the store itself.

The Brooked method

Brooked handles the pagination, coerces monetary strings to numbers so totals sum correctly, and imports orders and line items as separate related tables so you can report at either grain without double counting. Products, customers and coupons import the same way.

Step 1: Install Brooked

Install Brooked from the Google Workspace Marketplace. Free tier includes 100 imports per month, no credit card required.

Step 2: Connect WooCommerce

Choose WooCommerce in Brooked and enter your store URL with the consumer key and secret. Use a Read-only key unless you intend to write back. Confirm permalinks are not set to Plain first, since that single setting breaks every REST route.

Step 3: Schedule the refresh

Set the import to re-run hourly or daily. A scheduled re-read also picks up orders whose status changed after they were placed, refunds and cancellations in particular, which webhook-driven append-only feeds never revisit.

BrookedBrooked AI, WooCommerce
Live
Ask anything about your WooCommerce data…

Method comparison

MethodCostSetupRefreshTwo-wayBest for
WooCommerce CSV exportFree5 minManualProduct import onlyProduct catalogue exports
Apps Script + REST APIFree25 to 40 minTime-driven triggerDIYOrders and custom fields, no budget
WordPress export pluginsFree tier · paid for scheduling10 to 20 minScheduled (paid tiers)NoStore owners who prefer plugins to code
BrookedFree tier · Pro $29/user/mo~3 minScheduled (hourly, daily, weekly)YesScheduled sales reporting in Sheets

Common use cases

  • Sales reporting: daily and monthly revenue by product, category or coupon
  • Inventory planning: join stock levels against sales velocity to set reorder points
  • Customer analysis: repeat purchase rates and lifetime value from order history
  • Bulk price updates: edit prices in a sheet and write them back rather than clicking through wp-admin
  • Multi-store roll-ups: combine several WooCommerce stores into one reporting table

Troubleshooting common issues

Frequently asked questions

Why does my WooCommerce REST API URL return a 404?

Almost always the permalink setting. The /wp-json/ routes only exist when WordPress uses pretty permalinks; with Settings → Permalinks set to Plain, every REST URL 404s. Switch to Post name (or anything other than Plain) and re-save the permalinks page to flush the rewrite rules. If it still 404s, a security plugin or host rule may be blocking the REST API outright.

Why do I get 401 with correct consumer key and secret?

Many shared hosts strip the Authorization header before PHP sees it, so credentials never arrive. Two fixes: pass consumer_key and consumer_secret as query string parameters instead, which WooCommerce accepts over HTTPS, or add a rewrite rule that preserves the header. Also confirm your store is actually on HTTPS, since over plain HTTP WooCommerce requires OAuth 1.0a signatures rather than basic auth.

Can I connect WooCommerce to Google Sheets for free?

Yes. WooCommerce includes a built-in CSV exporter for products, and orders can be exported with free plugins, both at no cost. The Apps Script method in this guide uses free read-only API keys and a free time-driven trigger for data that refreshes. Brooked's free tier covers 100 imports a month.

How do I get more than 100 orders?

per_page maxes out at 100. Paginate with the page parameter and read the X-WP-TotalPages response header to know when to stop, or keep requesting until a page comes back empty. Ordering by date and paging through a large store is slow, so filter with the after and before parameters where you can.

How are line items structured in the API?

Each order contains a line_items array, so an order with three products is one JSON object containing three entries, not three rows. Decide which shape you want: one row per order with items summarised, or one row per line item with order fields repeated. Mixing the two is what produces revenue totals that double-count.

Can I write changes back to WooCommerce from Sheets?

Yes with a read/write API key. Bulk price changes, stock levels and order status updates can all be written back, and Brooked supports this. Create the key with Read/Write permission, and be deliberate about it: a bad bulk write against a live store is immediately visible to customers.

Connect WooCommerce to Google Sheets today.

Free tier: 100 imports per month, no credit card required. Or see the full WooCommerce integration details.

Install Brooked free →

Also in eCommerce

More eCommerce guides

eCommerce

How to Connect Shopify to Google Sheets

Sync Shopify orders and products to Google Sheets, including the 60-day order window that silently hides your history and the GraphQL cost limit that throttles big pulls.

JW
James Whitfield
Read

Get your spreadsheet hours back

Brooked sets up in seconds. Your team is querying live data before lunch.

Get started free