How to Build a Live Leaderboard from Google Sheets in WordPress

Updated July 2026 • 7 min read • By Fahad Murtaza

TableCrafter table builder, connect Gravity Forms, Google Sheets, Airtable, CSV, or JSON data sources
TableCrafter table builder, connect Gravity Forms, Google Sheets, Airtable, CSV, or JSON data sources

A live leaderboard is one of the best showcases for the Google Sheets + TableCrafter combination: the organizer updates scores in Sheets, and the embedded WordPress table reflects updated scores within the next WP-Cron sync cycle without anyone touching the site. This guide builds a complete leaderboard with rank column, score data bars, and top-3 status badges. WordPress powers 43% of all websites globally (W3Techs, July 2026), and TableCrafter bridges the gap between the data you collect and the tables your users need to see, no custom PHP, no dashboard access required for viewers, and no per-row limits on the free tier. The free version on WordPress.org supports CSV, JSON, Google Sheets, and Excel. Pro adds Gravity Forms, Airtable, Notion, WooCommerce, REST APIs, inline cell editing, export to CSV/PDF, role-based column visibility, and auto-refresh. Every table embeds on any page with a [tablecrafter] shortcode or the native Gutenberg block. In a 2024 study of business WordPress sites, 68% of teams needed non-admin users to update form data at least weekly (WP Engine Survey, 2024).

What Is the Architecture?

Your Google Sheet is the single source of truth. Organizers update it however they want: manually, via a Google Form, or via an Apps Script. TableCrafter uses WordPress-Cron to fetch fresh data from Google Sheets on a configurable sync schedule. The shortest available interval is every 15 minutes; longer options (hourly, twice-daily, daily) are also available, and a manual-only mode lets you trigger refreshes on demand without a scheduled job. Between syncs, the fetched data is stored in a WordPress transient. When a visitor loads the leaderboard page, TableCrafter checks the transient: if it is still valid, the cached rows are served immediately without any outbound request to Google; if it has expired, the next scheduled WP-Cron run fetches fresh data and repopulates the transient. Visitors see scores that are at most one sync interval old. No client-side polling, no auto-reload JavaScript, and no server-side page refresh is needed on the frontend to keep the data current. For a competition where scores change frequently, the 15-minute interval keeps rankings as current as the WP-Cron schedule allows.

This setting persists across table rebuilds. If you change the data source later, you may need to revisit this step to remap columns from the new source to the existing table configuration.

This configuration interacts with any caching or CDN layer active on your WordPress installation. If you use WP Rocket, LiteSpeed Cache, or a CDN such as Cloudflare, flush the page cache after making this change to ensure the updated configuration is reflected in the cached HTML served to visitors. TableCrafter's server-side output is regenerated on the next uncached request.

Step 1: How Do I Structure the Google Sheet?

Create a sheet with these columns in row 1:

Rank | Name | Team | Score | Status

Column notes:

Let Sheets do the ranking math. Using RANK() in Sheets means ties are handled correctly (two players with the same score both get rank 2, and rank 3 is skipped). TC displays whatever Sheets computes.

Step 2: How Do I Publish or Connect the Sheet?

For a public leaderboard where scores are meant to be seen by anyone, use the no-authentication CSV export. Google generates a public URL that returns the sheet as plain CSV, which TableCrafter fetches directly without any API credentials. The URL remains stable as long as you keep publishing settings enabled.

For a private competition where you want the data on your site but do not want the raw sheet accessible as a public URL, use the Google Sheets API v4 with an API key. This requires a Google Cloud project with the Sheets API enabled and a restricted API key scoped to the Sheets API and your domain. The sheet is never published to the web, so its contents are only reachable through your API credentials.

TableCrafter validates this configuration on save. If validation fails, the admin panel displays a specific error message identifying which field caused the problem. Correct the field value and save again without needing to restart the setup process.

After completing this step, verify the result by viewing the page as a logged-out visitor in an incognito window. This confirms the table behaves correctly for public visitors rather than reflecting admin-level permissions that may hide configuration issues during initial setup. Check both the rendered output and the browser console for any JavaScript errors.

Step 3: How Do I Create the Data Source in TableCrafter?

  1. Go to TableCrafter → Data Sources → Add New. TableCrafter will prompt you to select a source type before presenting the configuration form.
  2. Choose your connection type: Public CSV for a publicly published sheet (no credentials required), or Private API for a sheet accessed via the Google Sheets API v4 (requires an API key and Spreadsheet ID).
  3. Enter the published CSV URL (public mode) or the Spreadsheet ID and tab name (private mode). The Spreadsheet ID is the alphanumeric string in the sheet URL between /d/ and /edit. The tab name must match the sheet tab exactly, including capitalization and spacing.
  4. Set Sync Interval to 15 min. This is the shortest available schedule. TableCrafter registers a WP-Cron event that fires every 15 minutes, fetches fresh data from Google, and stores the result in a WordPress transient. Longer intervals (hourly, twice-daily, daily) are available if scores change less frequently and you want to reduce outbound API calls.
  5. Click Save and Fetch Preview to confirm the connection succeeds and columns are detected. If the preview returns no columns, verify the sheet is published to the web (public mode) or that the API key has Sheets API access enabled in your Google Cloud console (private mode).

Step 4: How Do I Map Columns for Leaderboard Display?

Column mapping tells TableCrafter what type each column contains and which display options to apply. The type you assign determines what features are available: Number columns support numeric sorting and data bars; Text columns support badge mode and dropdown filtering. In the column mapping interface, configure the following for each column from Step 1:

Configuring the Score Data Bar

Data bars are configured per column and stored under column_data_bars in the table settings. They require the column type to be set to Number. In TC's column editor for Score, enable Data Bar and configure the following fields:

Data bars will not render if Score cells contain non-numeric characters such as comma separators or currency symbols. Strip any formatting in Google Sheets before connecting the source: use a numeric-only column and let TC's column formatter handle display formatting separately.

Configuring Status Badges

Badge mode is configured per column and stored under column_badge_maps in the table settings. Each rule maps a specific text value to a background color and text color. Rules are matched exactly against the cell text after trimming whitespace. In TC's column editor for Status, enable Badge mode and add the following rules:

Badge values must match the Sheets formula output exactly. If your formula outputs Gold with a trailing space, the badge rule for Gold will not match. Wrap your Sheets formula in TRIM() to ensure clean values. Multiple rules are evaluated in order; the first matching rule wins.

Step 5: How Do I Create and Configure the Table?

  1. Go to TableCrafter → Tables → Add New. Give the table a descriptive internal title such as "Summer League Leaderboard 2026" so you can identify it if you create multiple tables later.
  2. Assign the leaderboard data source you created in Step 3. TableCrafter maps the source columns to the table's column configuration automatically on first assignment.
  3. Set Default sort column to Score, direction Descending. These settings are stored as default_sort_column and default_sort_direction in the table configuration. When a visitor first loads the table, the Score column is pre-sorted highest to lowest with no interaction required.
  4. Set Rows per page. The default is 25. For competitions with fewer than 25 participants, the pagination controls disappear automatically. For large competitions, 25 or 50 rows keeps the page manageable.
  5. Enable Search so visitors can find a specific player by name without scrolling through the sorted list.
  6. Enable Team filter if you mapped the Team column as filterable in Step 4. This builds a dropdown of all distinct team names and lets visitors narrow the board to one team's standings.
  7. Disable Export if you do not want participants downloading the full score list as a CSV file.
  8. Save the table. Note the assigned ID shown after saving, you will use it in the shortcode in Step 6.

Step 6: How Do I Embed on Your WordPress Page?

Edit the page where you want the leaderboard. In the Gutenberg editor, add a Shortcode block and paste the shortcode from Step 5. For a leaderboard with search and column filters:

[tablecrafter id="5" filter="true" search="true"]

For a fully automated leaderboard that shows the current top entries without any visitor controls, use the minimal form:

[tablecrafter id="5"]

Publish or update the page. The leaderboard is live and will reflect the current rankings from your Google Sheet on every page load (subject to the cache TTL you configured in Step 2). To verify the display is correct, view the page while logged out — the table should show the same data a visitor would see, with rankings sorted by your configured default sort column. After the next WP-Cron sync cycle runs at the interval you configured in Step 3, reload the page and confirm the rankings reflect the latest sheet data.

How Does Testing the Live Refresh Work?

  1. Open the leaderboard page in one browser tab. Note the current scores and rankings so you have a reference point.
  2. In a second browser tab, open the Google Sheet and change a score value for one participant, for example changing 850 to 950.
  3. Wait for the next WP-Cron sync cycle. If you set the sync interval to 15 minutes in Step 3, the update will appear within that window after the cron job fires. You can check when the last sync ran under TableCrafter → Data Sources → Last Synced timestamp on your leaderboard source.
  4. Reload the WordPress leaderboard page. The updated score and any recalculated rank values should appear in the table.

If the update does not appear after two full sync intervals, investigate at three layers: first, confirm the sync interval in the data source settings matches your expectation; second, verify WP-Cron is running on your server (some managed hosts disable or delay WP-Cron; use a real crontab entry calling wp cron event run --due-now if needed); third, check whether a full-page caching plugin such as WP Rocket, W3TC, or NitroPack is serving stale HTML. Exclude the leaderboard page URL from full-page caching, or use TC's AJAX rendering mode so the table data loads after the cached page shell.

Page-level caching vs. data caching: TC's sync interval (minimum 15 minutes, configured in Step 3) controls how often it fetches from Google and updates the WordPress transient. But if your WordPress host or caching plugin caches the entire HTML page, visitors receive stale rendered HTML regardless of how frequently TC syncs. Either exclude the leaderboard page from full-page caching, or use TC's AJAX rendering mode (available under Table Settings → Rendering) so the table data loads dynamically after the cached page shell is served.

What Is Advanced: Auto-Numbering Rank Without a Rank Column?

If you sort by Score descending and enable TC's Row number column option (under Table Settings → Display), TC automatically prepends a sequential row number to each row at render time. The number reflects the row's position in the sorted result set: the highest scorer receives row number 1, the next receives 2, and so on. For a simple competition where ties are not a concern, this eliminates the need for a Rank column in Sheets entirely, which simplifies the sheet structure and removes the dependency on a RANK() formula.

The important limitation is that row numbers do not handle ties the way a proper ranking formula does. If two participants share the same score, they receive consecutive row numbers (for example 2 and 3) rather than the same rank. The row-number display reads 1, 2, 3 even when positions 2 and 3 are tied. For a competition where accurate tie-handling matters, keep the Rank column in Sheets with a =RANK(D2,$D$2:$D$100,0) formula and display it as a regular number column so that tied participants share the same rank value and the next position is skipped correctly.

The setting is stored in the WordPress options table under the table's configuration key. It does not modify the original data source and can be changed at any time without affecting the underlying records.

The column mapping you define here is stored as a JSON configuration in the WordPress database. You can export this configuration using the TableCrafter export tool and import it to another table or another site. This is useful when replicating a table layout across multiple pages or when migrating a table to a staging environment for testing before going live.

Frequently Asked Questions

What Is the Architecture?

Your Google Sheet is the single source of truth. Organizers update it manually, via a form, or via a script. TableCrafter uses WP-Cron to fetch fresh data from Google Sheets on a configurable sync schedule (minimum 15 minutes) and stores the result in a WordPress transient. Visitors see scores that are at most one sync interval old, without any client-side polling or page-reload mechanism on the frontend.

What Is TableCrafter?

TableCrafter is a WordPress plugin that turns data from Gravity Forms, Google Sheets, Airtable, Notion, REST APIs, CSV files, and WooCommerce into interactive, sortable, filterable frontend tables. Embed any table on any WordPress page with the [tablecrafter] shortcode or the native Gutenberg block. No PHP or custom development required. The free version supports CSV, JSON, Google Sheets, and Excel. Pro adds Gravity Forms, Airtable, Notion, WooCommerce, REST APIs, inline cell editing, export to CSV and PDF, role-based column visibility, and auto-refresh.

Does this require PHP or developer skills?

No. TableCrafter is configured entirely through the WordPress admin interface. You choose your data source, map fields to columns, and set display preferences using point-and-click controls. Embedding uses the [tablecrafter] shortcode or the native Gutenberg block.

Is the free version sufficient or do I need Pro?

The free plugin on WordPress.org supports CSV, JSON, Google Sheets, and Excel sources with unlimited tables, rows, and columns. Pro adds Gravity Forms, Airtable, Notion, WooCommerce, REST API sources, inline cell editing, bulk row actions, export to CSV and PDF, role-based column visibility, and auto-refresh every N seconds.

Ready to try it?

TableCrafter is free on WordPress.org. Pro unlocks inline editing, role-based permissions, and advanced data sources.

Changes take effect immediately after saving. No cache flush or page refresh is required for the new configuration to apply to all shortcode instances of this table.

TableCrafter re-fetches this data on each page load by default. If your data source updates infrequently and your site has significant traffic, enable the built-in caching option in the table's Performance tab. This stores the fetched data for a configurable number of minutes and serves it from WordPress transients, reducing API calls to the source and improving page load time for visitors.