Private & API-Key Google Sheets

TableCrafter reads Google Sheets through Google's own published CSV export endpoint, not the Google Sheets API. This page documents exactly which sharing modes and URL formats work, what "API key" means in practice, and why truly private sheets cannot be reached by the free engine.

Google Sheets CSV Export Link Sharing SSRF-Safe SWR Cache

How TableCrafter actually reads a sheet

TableCrafter does not call sheets.googleapis.com and it does not perform OAuth. Instead, when the source URL matches a Google Sheets pattern, the data fetcher rewrites it to Google's public CSV export URL and downloads the resulting comma-separated text over HTTPS. The detection is a single regular expression in both includes/class-tc-data-fetcher.php and includes/sources/class-tc-csv-source.php:

// Matches any docs.google.com spreadsheet link
preg_match('/docs\.google\.com\/spreadsheets\/d\/([a-zA-Z0-9-_]+)/', $url, $matches);

Any matching URL is normalized to the export form before the request is made:

https://docs.google.com/spreadsheets/d/{SHEET_ID}/export?format=csv

If your original link contains a gid query parameter (the numeric tab identifier), it is preserved so the correct worksheet tab is exported:

.../export?format=csv&gid=0
â„šī¸

Because the engine converts everything to a CSV download, a Google Sheet is treated internally as a CSV data source. The same parser, BOM handling, and caching apply to both.

What "private" and "API key" really mean here

The free TableCrafter engine has no concept of a stored Google credential, service account, or per-request API key. There is no api_key shortcode attribute and no OAuth flow. Authentication is determined entirely by the sheet's own Google sharing setting and by what is embedded in the URL:

âš ī¸

For header-based or OAuth-authenticated Google access, the free version cannot help. The plugin's own FAQ directs OAuth / header-auth needs to the Pro tier or a custom integration. Do not expect a private, account-restricted sheet to load by pasting its edit URL.

Preparing your sheet in Google

  1. Open the sheet in Google Sheets.
  2. Click Share, then under General access choose Anyone with the link and set the role to Viewer.
  3. Copy the browser URL. Either the editor URL or a published URL will work because TableCrafter only needs the spreadsheet ID.
  4. If you want a specific tab, note its gid value from the URL fragment (for example #gid=123456).

Supported URL formats

Any of the following are accepted. They all funnel through the same CSV normalization once the /spreadsheets/d/{ID} pattern is recognized.

URL formNotes
Editor URL .../d/{ID}/edit#gid=0Most common. The gid from the query string is carried over to select the tab.
Export URL .../d/{ID}/export?format=csvAlready the canonical form; passes through unchanged.
Visualization URL .../d/{ID}/gviz/tq?tqx=out:csvThe format recommended in the Elementor widget helper. Still matched by the spreadsheet regex and treated as CSV.
Published-to-web CSV linkWorks as a plain remote CSV as long as it ends in .csv or matches the spreadsheet pattern.
💡

When a sheet has multiple tabs, always include the right gid. Without it, Google exports the first tab, which may not be the data you expect.

Connect from the admin builder

The dashboard offers a one-click helper so you do not have to construct the URL by hand:

  1. Go to wp-admin → TableCrafter.
  2. In the Shortcode Builder, click the Google Sheets button (rendered with the spreadsheet icon).
  3. Paste your link into the prompt. The label is explicit: "Paste your Google Sheet URL (Must be 'Anyone with the link can view')".
  4. The URL is dropped into the source field and a preview is triggered automatically so you can confirm the data parses before copying the shortcode.

The handler is wired to the #tc-google-sheet-btn element in assets/js/admin.js; it does not store any token, it simply fills the source field.

Shortcode usage

The only required attribute is source. Everything else mirrors a standard CSV/JSON table.

AttributeRequiredPurpose
sourceRequiredThe Google Sheet link (edit, export, or gviz form).
includeOptionalComma-separated columns to show; supports key:Alias renaming.
excludeOptionalComma-separated columns to hide.
searchOptionalLive search bar (true/false).
filtersOptionalPer-column filters (default true).
per_pageOptionalRows per page; 0 shows all.
sortOptionalcolumn:direction, e.g. price:desc.
exportOptionalEnable CSV / clipboard export tools.
auto_refreshOptionalPeriodically re-fetch the sheet (true/false).
refresh_intervalOptionalRefresh period in milliseconds (default 300000).

Note that root has no effect on a Google Sheet: it is a JSON-only path selector, and CSV data has no nested root.

Basic public sheet

[tablecrafter source="https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit"]

Specific tab with search and pagination

[tablecrafter
  source="https://docs.google.com/spreadsheets/d/1BxiMVs0.../edit#gid=123456"
  search="true"
  per_page="15"]

Curated columns, sorted, with export

[tablecrafter
  source="https://docs.google.com/spreadsheets/d/1BxiMVs0.../gviz/tq?tqx=out:csv"
  include="name,region,revenue:Revenue (USD)"
  sort="revenue:desc"
  export="true"]

How rows and headers are parsed

The CSV parser in TC_CSV_Source::parse() applies a few rules worth knowing when designing your sheet:

💡

Keep a clean, rectangular data range. Avoid merged cells, header rows above the data, or summary rows with a different column count, since those rows are discarded during parsing.

Security and SSRF protection

Every remote source, including Google Sheets, passes through TC_Security::is_safe_url(), which delegates to WordPress core's wp_http_validate_url() to block private and loopback addresses before any request is made. The fetch itself uses cURL with full SSL verification enabled (CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST) and the WordPress-bundled CA certificates, so the connection to Google is authenticated and cannot be silently downgraded.

âš ī¸

Anyone who can read the rendered table can also read the sheet's data, and the sheet must be link-shared publicly for it to load. Do not place confidential information in a sheet you connect this way.

Caching and refresh behavior

Fetched sheet data is cached using a stale-while-revalidate (SWR) strategy. The first render fetches synchronously and stores the result; subsequent loads serve the cached copy instantly. When the cached HTML is older than five minutes, a background refresh is scheduled, and the underlying data cache uses a one-hour TTL. For tables that change often, add auto_refresh="true" with a suitable refresh_interval to re-pull the export on a timer.

Troubleshooting

SymptomLikely cause and fix
"Source returned HTTP 401/403" or a login pageThe sheet is still private. Set sharing to "Anyone with the link can view."
Wrong tab's data appearsThe gid was missing or wrong. Append the correct #gid= from the sheet URL.
Some rows are missingThose rows did not match the header column count. Remove merged cells and ragged columns.
First column name looks garbledUsually a BOM, which is stripped automatically; re-save the sheet if it persists.
Table shows old dataSWR cache is serving a stale copy. Wait for the background refresh or enable auto_refresh.

Next, see csv-files.html for the shared CSV parsing rules that govern these tables, and auto-refresh.html for tuning live updates on a Google Sheets source.