Sync a Jira Filter (JQL) to Google Sheets Automatically

The filter already exists in Jira. Automatically here means it runs on its own after you set it up once, not that you keep exporting it by hand.

Start from the filter you already have

Most teams already have a saved Jira filter, or could write the JQL for one in a minute: open issues assigned to a team, everything in the current sprint, a support queue filtered by status. That query is the report. The automation problem isn't finding the right JQL, it's getting Jira's answer to that query into a sheet without re-running it by hand every time someone asks for an update.

What "automatically" needs to cover

  1. Run the JQL or saved filter itself, not a manually curated subset of it.
  2. Page through the full result set. Jira's search API returns results a page at a time, and a filter that matches more than one page needs to keep requesting until it's exhausted, not stop at the first response.
  3. Write the result to a sheet tab on a schedule, hourly, daily, or weekly, without someone remembering to click export.
  4. Flatten custom fields into readable cells instead of raw API objects, since most saved filters include at least one custom field alongside the standard ones.

Where a plain export falls short

The Issue Navigator's CSV export button, or the older /search endpoint some scripts call, work fine for a one-off download. Neither is built to be a standing report: the CSV button has its own separate cap Atlassian raised to 10,000 issues, and neither one refreshes itself. See why Jira's CSV export still caps at 10,000 issues and how to export more than 1,000 Jira issues for the mechanics of paging past a single response.

Building it against the current search API

Atlassian's REST API v3 offers two ways to run a JQL search: the deprecated offset-based GET /rest/api/3/search, and the current, token-paged POST /rest/api/3/search/jql. The current endpoint is a POST rather than a GET specifically because a long JQL string plus a large field list can exceed the roughly 2,082-character URL limit most HTTP clients and proxies enforce; putting the query in the request body avoids that ceiling entirely. Authentication is HTTP Basic with your Atlassian account email as the username and an API token, generated from id.atlassian.com → Security → API tokens, as the password, not your actual login password. Each response returns a page of issues plus a continuation token; a script has to keep requesting with that token until Jira signals there's no more data, since stopping after the first page silently truncates the result exactly the way a naive CSV pull would.

Native automation tools vs. building it vs. Sheet Sync for Jira

 CSV export buttonBuild on the APISheet Sync for Jira
Refreshes itselfNoOnly if you build the triggerYes, hourly/daily/weekly
Result size limit10,000 issuesNone, if pagination is correct500 on Free, none on Pro
Custom fields readable as textPartiallyOnly if you write the flattening logicYes, built in
SetupA menu clickAn API token, pagination, a triggerConnect a token, save the query

Fields still need to come out clean

A JQL result that includes user, option, array, or rich-text custom fields, common in any filter built for reporting rather than a quick lookup, returns those fields as typed objects, not text. Rich-text fields in particular arrive as Atlassian Document Format (ADF), a nested JSON tree describing formatting, not a plain string, so pulling a description or a rich-text custom field means recursively walking that structure to extract readable text rather than reading one property off it. A schedule just repeats whatever the first run produced, so a broken column stays broken on every refresh. See why Jira custom fields export as [object Object] or raw JSON before you set the schedule and forget about it, or pulling Jira issue status into Google Sheets if status specifically is the column that matters.

What "connect a token, save the query" actually involves

Sheet Sync for Jira adds one item under Extensions → Sheet Sync for Jira. Opening it the first time asks for a Jira site URL, an Atlassian account email, and an API token from id.atlassian.com → Security → API tokens, the same token type the manual build above needs; nothing beyond that read-only token leaves the spreadsheet owner's own Google Apps Script project. A new import then picks JQL or a saved filter, the fields to bring across, a destination tab, and a refresh cadence. There's no separate deploy step and no trigger to wire up by hand: saving the import is what creates the shared hourly dispatcher behind the scenes.

Troubleshooting

The sync stops partway through a large filter

Check whether the continuation token from search/jql was actually followed to the end. A script or Zap that reads only the first response's issues array will look like it worked on a small filter and then quietly truncate the moment the same filter matches more than one page.

A 401 or 403 comes back where the query used to work

API tokens can be revoked from id.atlassian.com independently of the account's Jira password, and a token used with the wrong Atlassian account email in the Basic auth header fails the same way a wrong password would.

Point it at a filter, not a script

Sheet Sync for Jira runs JQL or a saved filter directly against the current search/jql endpoint, pages through the full result with a resumable cursor, flattens every field type including ADF rich text, and refreshes on a schedule you set once.

See Sheet Sync for Jira