DEV Community

Cover image for Solved: Syncing WooCommere Inventory with Google Sheets Real-time
Darian Vance
Darian Vance

Posted on • Originally published at wp.me

Solved: Syncing WooCommere Inventory with Google Sheets Real-time

πŸš€ Executive Summary

TL;DR: Manual WooCommerce inventory synchronization with Google Sheets is inefficient and error-prone, often requiring expensive, rigid third-party tools. This guide provides a robust, cost-effective solution using a custom Python script to achieve real-time inventory sync via WooCommerce REST API and Google Sheets API, offering granular control and eliminating manual effort.

🎯 Key Takeaways

  • The solution leverages WooCommerce REST API for product data retrieval and Google Sheets API for updating inventory, ensuring data accuracy and automation.
  • Secure credential management is crucial, recommending environment variables for WooCommerce API keys (Consumer Key, Consumer Secret) and a Google Service Account JSON key for Sheets API access.
  • The Python script handles pagination for fetching all WooCommerce products (simple and variable) and uses batch updates for Google Sheets to optimize API calls and prevent rate limiting.

Syncing WooCommere Inventory with Google Sheets Real-time

As a Senior DevOps Engineer at TechResolve, I constantly encounter scenarios where manual data synchronization becomes a bottleneck, draining resources and introducing errors. The problem intensifies for e-commerce businesses dealing with dynamic inventory, such as those running on WooCommerce.

Imagine this: you're managing a WooCommerce store, products are selling, and new stock is arriving. Keeping your inventory accurate across various platforms, especially for reporting and analysis in tools like Google Sheets, often involves tedious manual exports and imports. This not only consumes valuable time but also leads to discrepancies, stockouts, or overselling, directly impacting customer satisfaction and revenue. Expensive third-party synchronization tools often come with rigid features and hefty subscription fees, locking you into a predefined ecosystem.

This tutorial offers a robust, cost-effective, and highly customizable solution: real-time synchronization of your WooCommerce inventory directly into Google Sheets using a custom Python script. We will leverage the power of WooCommerce's REST API and Google Sheets API to create an automated, reliable pipeline that ensures your inventory data in Google Sheets is always up-to-date, reflecting the current state of your WooCommerce store. This approach provides granular control, allowing you to tailor the synchronization logic precisely to your business needs.

Prerequisites

Before we dive into the implementation, ensure you have the following in place:

  • WooCommerce Store: An active WooCommerce store with the REST API enabled. This typically means navigating to WooCommerce > Settings > Advanced > REST API.
  • Google Cloud Project: A Google Cloud Platform (GCP) project with the Google Sheets API enabled. If you don't have one, creating a new project is straightforward.
  • Google Service Account: A service account within your GCP project, granted appropriate permissions to access and modify your Google Sheet.
  • Python 3.x: Python 3.6 or newer installed on your development machine or server.
  • Python Libraries: You'll need to install the Google API Client Library for Python and the WooCommerce REST API client.
  • Google Sheet: An existing Google Sheet where you intend to sync your inventory data. Make sure it's shared with your service account's email address.

Step-by-Step Guide: Syncing WooCommerce Inventory

This guide will walk you through the entire process, from setting up API access to writing and scheduling the synchronization script.

Step 1: Set Up WooCommerce REST API Keys

First, we need to generate API keys in your WooCommerce store to allow our script to interact with it.

  1. Navigate to your WordPress dashboard.
  2. Go to WooCommerce > Settings > Advanced > REST API.
  3. Click "Add key".
  4. Provide a description (e.g., "Google Sheets Sync").
  5. Select a user for the API key.
  6. Set the Permissions to "Read/Write" to allow fetching product data and potentially updating it if your future plans involve two-way sync.
  7. Click "Generate API key".
  8. Note down the Consumer Key and Consumer Secret. These will only be shown once. Treat them like passwords.

For security, we recommend storing these keys as environment variables rather than hardcoding them into your script.

# Example of setting environment variables (replace with your actual keys)
# export WC_CONSUMER_KEY="ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# export WC_CONSUMER_SECRET="cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# export WC_STORE_URL="https://yourstore.com"
Enter fullscreen mode Exit fullscreen mode

Step 2: Configure Google Sheets API Access

Next, we'll set up access to the Google Sheets API through a service account.

  1. Go to the Google Cloud Console.
  2. Select or create a new project.
  3. Navigate to APIs & Services > Library. Search for "Google Sheets API" and enable it.
  4. Go to APIs & Services > Credentials.
  5. Click "CREATE CREDENTIALS" and choose "Service Account".
  6. Give your service account a name (e.g., "woo-sheets-sync") and a description. Click "CREATE AND CONTINUE".
  7. For "Grant this service account access to project", you can assign roles like "Project > Viewer" or "Basic > Editor" if you need broader permissions, but for Sheets access, "Editor" might be sufficient on the sheet itself. Click "DONE".
  8. Back on the "Credentials" page, find your newly created service account and click on its email address.
  9. Go to the "KEYS" tab, click "ADD KEY > Create new key", select "JSON", and click "CREATE". This will download a JSON file to your computer. Rename it to something like service_account_key.json and store it securely.
  10. Open your target Google Sheet. Click "Share" and add the email address of your service account (found in the JSON key file under client_email) with "Editor" permissions.
  11. Note down your Spreadsheet ID. This is the long alphanumeric string in the URL of your Google Sheet between d/ and /edit.

Store the path to your service account key and the spreadsheet ID as environment variables:

# export GOOGLE_SHEETS_KEY_PATH="/path/to/your/service_account_key.json"
# export GOOGLE_SHEET_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# export GOOGLE_SHEET_RANGE="Sheet1!A:D" # Adjust to your sheet name and column range
Enter fullscreen mode Exit fullscreen mode

Step 3: Develop the Python Synchronization Script

Now, let's write the Python script that fetches data from WooCommerce and pushes it to Google Sheets.

First, install the necessary libraries:

pip install woocommerce google-auth google-auth-httplib2 google-auth-oauthlib google-api-python-client
Enter fullscreen mode Exit fullscreen mode

Here's the core Python script:

import os
import json
from woocommerce import API
from google.oauth2 import service_account
from googleapiclient.discovery import build

# --- Configuration (from Environment Variables for security) ---
WOO_COMMERCE_URL = os.environ.get("WC_STORE_URL")
WOO_COMMERCE_KEY = os.environ.get("WC_CONSUMER_KEY")
WOO_COMMERCE_SECRET = os.environ.get("WC_CONSUMER_SECRET")

GOOGLE_SHEETS_KEY_PATH = os.environ.get("GOOGLE_SHEETS_KEY_PATH")
GOOGLE_SHEET_ID = os.environ.get("GOOGLE_SHEET_ID")
GOOGLE_SHEET_RANGE = os.environ.get("GOOGLE_SHEET_RANGE", "Inventory!A:Z") # Default range

# --- Initialize WooCommerce API ---
wcapi = API(
    url=WOO_COMMERCE_URL,
    consumer_key=WOO_COMMERCE_KEY,
    consumer_secret=WOO_COMMERCE_SECRET,
    version="wc/v3"
)

# --- Initialize Google Sheets API ---
SCOPES = ["https://www.googleapis.com/auth/spreadsheets"]
creds = service_account.Credentials.from_service_account_file(GOOGLE_SHEETS_KEY_PATH, scopes=SCOPES)
service = build("sheets", "v4", credentials=creds)

def fetch_woocommerce_inventory():
    print("Fetching inventory from WooCommerce...")
    products_data = []
    page = 1
    while True:
        try:
            # Fetch products with pagination. Per_page up to 100 is allowed.
            response = wcapi.get("products", params={"per_page": 100, "page": page}).json()
            if not response:
                break # No more products

            for product in response:
                # Basic product data extraction
                sku = product.get("sku")
                stock_quantity = product.get("stock_quantity")
                name = product.get("name")
                product_id = product.get("id")

                # Handle variations if necessary (example for parent product)
                if product.get("type") == "variable":
                    # Fetch variations for variable products
                    variations_response = wcapi.get(f"products/{product_id}/variations").json()
                    for variation in variations_response:
                        var_sku = variation.get("sku")
                        var_stock = variation.get("stock_quantity")
                        var_name = f"{name} - {' '.join([attr['option'] for attr in variation['attributes']])}"
                        products_data.append([var_sku, var_name, var_stock, product_id, variation.get("id")])
                else:
                    # Simple products
                    products_data.append([sku, name, stock_quantity, product_id, '']) # Empty for variation ID

            page += 1
            print(f"Fetched page {page-1}")

        except Exception as e:
            print(f"Error fetching WooCommerce products: {e}")
            break

    print(f"Finished fetching {len(products_data)} items from WooCommerce.")
    return products_data

def sync_to_google_sheets(woo_inventory_data):
    print("Syncing inventory to Google Sheets...")
    try:
        # Get existing sheet data
        result = service.spreadsheets().values().get(spreadsheetId=GOOGLE_SHEET_ID, range=GOOGLE_SHEET_RANGE).execute()
        existing_sheet_values = result.get("values", [])

        # Assume the first row is headers and should not be modified
        header = existing_sheet_values[0] if existing_sheet_values else ["SKU", "Product Name", "Stock Quantity", "Product ID", "Variation ID"]
        data_rows = existing_sheet_values[1:] if existing_sheet_values else []

        # Create a mapping for existing SKUs to their row index
        # Assuming SKU is in the first column (index 0) of your sheet
        sku_to_row_index = {row[0]: i + 1 for i, row in enumerate(data_rows) if row and row[0]} # +1 for 0-indexed data_rows offset by header

        updates = []
        new_rows = []

        # Iterate through WooCommerce data and prepare updates/new rows
        for item_data in woo_inventory_data:
            sku, name, stock, product_id, variation_id = item_data

            if sku in sku_to_row_index:
                row_index = sku_to_row_index[sku]
                # Check if an update is actually needed (e.g., stock quantity changed)
                # This simple check assumes stock quantity is in the 3rd column (index 2)
                if len(data_rows[row_index -1]) > 2 and str(data_rows[row_index -1][2]) != str(stock):
                    print(f"Updating SKU {sku}: Stock {data_rows[row_index -1][2]} -> {stock}")
                    # Prepare the update for the specific cell
                    updates.append({
                        'range': f"{GOOGLE_SHEET_RANGE.split('!')[0]}!C{row_index + 1}", # C column for stock, +1 for header offset
                        'values': [[stock]]
                    })
                    # Optionally update other fields if they change
                    updates.append({
                        'range': f"{GOOGLE_SHEET_RANGE.split('!')[0]}!B{row_index + 1}", # B column for name
                        'values': [[name]]
                    })
            else:
                print(f"Adding new SKU: {sku}")
                new_rows.append(item_data)

        # Apply batch updates for existing rows
        if updates:
            body = {'valueInputOption': 'RAW', 'data': updates}
            service.spreadsheets().values().batchUpdate(spreadsheetId=GOOGLE_SHEET_ID, body=body).execute()
            print(f"Applied {len(updates)} updates to existing rows.")

        # Append new rows
        if new_rows:
            body = {'values': new_rows}
            result = service.spreadsheets().values().append(
                spreadsheetId=GOOGLE_SHEET_ID, 
                range=GOOGLE_SHEET_RANGE, 
                valueInputOption='RAW', 
                insertDataOption='INSERT_ROWS', 
                body=body
            ).execute()
            print(f"Appended {len(new_rows)} new rows.")

        print("Synchronization complete.")

    except Exception as e:
        print(f"Error syncing to Google Sheets: {e}")

if __name__ == "__main__":
    inventory = fetch_woocommerce_inventory()
    if inventory:
        sync_to_google_sheets(inventory)
    else:
        print("No inventory data to sync.")
Enter fullscreen mode Exit fullscreen mode

Code Logic Explained:

  • Configuration: Reads sensitive credentials from environment variables, enhancing security.
  • API Initialization: Sets up connections to both WooCommerce and Google Sheets APIs using the provided keys and service account credentials.
  • fetch_woocommerce_inventory():
    • Utilizes the wcapi.get("products") method to retrieve product data.
    • Implements pagination (per_page and page parameters) to fetch all products, as APIs typically limit the number of items per request.
    • Handles both simple and variable products, extracting SKU, product name, stock quantity, product ID, and variation ID. This structure ensures comprehensive inventory tracking.
  • sync_to_google_sheets():
    • First, it reads the current data from your Google Sheet using service.spreadsheets().values().get(). This is crucial for updating existing rows rather than simply appending everything.
    • It creates a sku_to_row_index mapping to quickly find which row in the sheet corresponds to a given WooCommerce SKU.
    • Iterates through the fetched WooCommerce inventory:
    • If an SKU exists in the sheet, it prepares an update for the specific cells (e.g., stock quantity) using batchUpdate to minimize API calls.
    • If an SKU is new, it adds it to a list of new_rows to be appended.
    • Finally, it executes batch updates for modified rows and appends new rows using service.spreadsheets().values().append(). The valueInputOption='RAW' ensures that values are inserted as-is.

Step 4: Schedule and Deploy the Script

For "real-time" syncing, we need to run this script at regular intervals. A common and straightforward method on Linux-based systems is using cron.

  1. Save the Python script as sync_inventory.py in a directory, for example, /opt/woo_sync/.
  2. Create a shell script to set environment variables and run your Python script. Let's call it run_sync.sh:
#!/bin/bash

# Set your environment variables (replace with your actual values)
export WC_STORE_URL="https://yourstore.com"
export WC_CONSUMER_KEY="ck_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export WC_CONSUMER_SECRET="cs_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export GOOGLE_SHEETS_KEY_PATH="/opt/woo_sync/service_account_key.json"
export GOOGLE_SHEET_ID="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
export GOOGLE_SHEET_RANGE="Inventory!A:E" # Match your sheet name and columns

# Navigate to script directory
cd /opt/woo_sync/

# Activate virtual environment if you're using one
# source venv/bin/activate

# Run the Python script
python3 sync_inventory.py >> /var/log/woo_sync.log 2>&1
Enter fullscreen mode Exit fullscreen mode
  1. Make the shell script executable: chmod +x /opt/woo_sync/run_sync.sh.
  2. Open your crontab for editing: crontab -e.
  3. Add a line to schedule the script. For example, to run every 5 minutes:
# Run WooCommerce inventory sync every 5 minutes
*/5 * * * * /opt/woo_sync/run_sync.sh
Enter fullscreen mode Exit fullscreen mode

This cron job will execute your script every five minutes, effectively providing near real-time synchronization. Logs will be redirected to /var/log/woo_sync.log for monitoring.

Common Pitfalls

  • API Rate Limits: Both WooCommerce and Google Sheets APIs have rate limits. If you have an extremely large inventory or run the script too frequently, you might hit these limits. The WooCommerce client automatically handles some retries, but for Google Sheets, consider adding exponential backoff to your API calls or spacing out your cron jobs. For Google Sheets, batching updates (as done in the script) helps reduce the number of API requests.
  • Authentication and Permissions: Ensure your WooCommerce API keys have "Read/Write" permissions. For Google Sheets, double-check that your service account key path is correct and that the Google Sheet itself is explicitly shared with the service account's email address with "Editor" permissions. Mismatched environment variables or typos are frequent causes of "401 Unauthorized" or "403 Permission Denied" errors.

Conclusion

You've successfully built and deployed a custom solution for syncing your WooCommerce inventory with Google Sheets in near real-time. This automation eliminates manual effort, drastically improves data accuracy, and frees up valuable time for strategic tasks. By owning this integration, you gain complete control over your data flow, adapting it to your unique business needs without vendor lock-in or recurring subscription costs.

Consider enhancing this solution further by implementing WooCommerce webhooks for truly instantaneous updates, robust error logging and notification mechanisms (e.g., via Slack or email), or integrating with other data sources to build a comprehensive analytics dashboard in Google Sheets. The foundation is laid; the possibilities for further automation and insights are limitless.


Darian Vance

πŸ‘‰ Read the original article on TechResolve.blog


β˜• Support my work

If this article helped you, you can buy me a coffee:

πŸ‘‰ https://buymeacoffee.com/darianvance

Top comments (0)