Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 
  • Community
  • Q&A
  • Jira
  • Questions
  • How can I get a list of all filters on my site including name, id, jql, owner and when last used?

How can I get a list of all filters on my site including name, id, jql, owner and when last used?

Adam Sterrie
January 20, 2026

Hi,

We need to migrate from our site to merge with another site.

During the migration, some custom fields and other data will be renamed.

Consequently, many filters will break and any boards, dashboards, plans, etc. will break too.

We have over 22,000 filters. Manually checking all our filters for jql that will be affected by renaming is not feasible. So, I need a way to list all the filters (not just the ones shared to the public), including filter name, id, jql, owner and when last used.

I tried the Jira API but that only returns filters that are shared publicly even though I am a site-admin.

Any suggestions?

3 answers

1 vote
Shalini Pradhan
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
January 20, 2026

Hello @Adam Sterrie ,

Good day! Welcome to Atlassian Community :)

Currently, in Jira cloud, on UI, its not possible to get all the details. However you can use REST API to get certain details like JQL, filter ID, Filter owner and Filter name.

https://your-domain.atlassian.net/rest/api/3/filter/search?expand=owner,jql

There are few feature requests for the same:

However if you need data for reference purposes before site migration, you can contact our support team here: https://support.atlassian.com/contact/ 

They will help you by exporting all the details from the backend database.

Thank you

0 votes
Nikola Perisic
Community Champion
January 20, 2026

Hello @Adam Sterrie , you can try with this Python code:

import requests

from requests.auth import HTTPBasicAuth

import json

from datetime import datetime

import sys

# ============================================================================

# CONFIGURATION - Update these variables with your Jira credentials

# ============================================================================

JIRA_URL = "" # Your Jira instance URL

JIRA_EMAIL = "" # Your Jira email address

JIRA_API_TOKEN = "" # Your Jira API token

# ============================================================================

def get_all_filters(jira_url, auth):

"""

Fetch all filters accessible to the user.

Args:

jira_url: Base Jira URL

auth: HTTPBasicAuth object

Returns:

List of filter dictionaries

"""

filters = []

start_at = 0

max_results = 50

while True:

# API endpoint to get filters

url = f"{jira_url}/rest/api/3/filter/search"

params = {

'startAt': start_at,

'maxResults': max_results,

'expand': 'jql,owner,sharePermissions'

}

try:

response = requests.get(url, auth=auth, params=params)

response.raise_for_status()

data = response.json()

filters.extend(data.get('values', []))

# Check if there are more results

if start_at + max_results >= data.get('total', 0):

break

start_at += max_results

except requests.exceptions.RequestException as e:

print(f"Error fetching filters: {e}", file=sys.stderr)

if hasattr(e, 'response') and e.response is not None:

print(f"Response: {e.response.text}", file=sys.stderr)

sys.exit(1)

return filters

def format_last_viewed(last_viewed):

"""

Format the last viewed timestamp.

Args:

last_viewed: ISO format timestamp string or None

Returns:

Formatted date string or 'Never'

"""

if not last_viewed:

return 'Never'

try:

dt = datetime.fromisoformat(last_viewed.replace('Z', '+00:00'))

return dt.strftime('%Y-%m-%d %H:%M:%S')

except Exception:

return last_viewed

def is_public_filter(filter_data):

"""

Check if a filter is shared publicly.

Args:

filter_data: Filter dictionary

Returns:

Boolean indicating if filter is public

"""

share_permissions = filter_data.get('sharePermissions', [])

for permission in share_permissions:

if permission.get('type') == 'global':

return True

return False

def print_filters_table(filters):

"""

Print filters in a formatted table.

Args:

filters: List of filter dictionaries

"""

if not filters:

print("No filters found.")

return

# Print header

print(f"\n{'ID':<10} {'Name':<40} {'Owner':<30} {'Public':<8} {'Last Viewed':<20}")

print("=" * 108)

# Print each filter

for f in filters:

filter_id = f.get('id', 'N/A')

name = f.get('name', 'N/A')[:39] # Truncate if too long

owner_name = f.get('owner', {}).get('displayName', 'N/A')[:29]

is_public = 'Yes' if is_public_filter(f) else 'No'

last_viewed = format_last_viewed(f.get('viewUrl')) # Note: lastViewed may not be available

print(f"{filter_id:<10} {name:<40} {owner_name:<30} {is_public:<8} {last_viewed:<20}")

print(f"\nTotal filters: {len(filters)}")

def print_filters_detailed(filters):

"""

Print detailed information for each filter.

Args:

filters: List of filter dictionaries

"""

if not filters:

print("No filters found.")

return

for i, f in enumerate(filters, 1):

print(f"\n{'='*80}")

print(f"Filter #{i}")

print(f"{'='*80}")

print(f"ID: {f.get('id', 'N/A')}")

print(f"Name: {f.get('name', 'N/A')}")

print(f"Description: {f.get('description', 'N/A')}")

print(f"Owner: {f.get('owner', {}).get('displayName', 'N/A')} ({f.get('owner', {}).get('emailAddress', 'N/A')})")

print(f"JQL: {f.get('jql', 'N/A')}")

print(f"Public: {'Yes' if is_public_filter(f) else 'No'}")

print(f"Favorite: {f.get('favourite', False)}")

print(f"View URL: {f.get('viewUrl', 'N/A')}")

print(f"Search URL: {f.get('searchUrl', 'N/A')}")

def export_to_json(filters, filename='jira_filters.json'):

"""

Export filters to JSON file.

Args:

filters: List of filter dictionaries

filename: Output filename

"""

try:

with open(filename, 'w', encoding='utf-8') as f:

json.dump(filters, f, indent=2, ensure_ascii=False)

print(f"\nFilters exported to {filename}")

except Exception as e:

print(f"Error exporting to JSON: {e}", file=sys.stderr)

def export_to_csv(filters, filename='jira_filters.csv'):

"""

Export filters to CSV file.

Args:

filters: List of filter dictionaries

filename: Output filename

"""

try:

import csv

with open(filename, 'w', newline='', encoding='utf-8') as f:

writer = csv.writer(f)

# Write header

writer.writerow(['ID', 'Name', 'Owner Name', 'Owner Email', 'JQL', 'Public', 'Favorite', 'Description', 'View URL'])

# Write data

for filter_data in filters:

writer.writerow([

filter_data.get('id', ''),

filter_data.get('name', ''),

filter_data.get('owner', {}).get('displayName', ''),

filter_data.get('owner', {}).get('emailAddress', ''),

filter_data.get('jql', ''),

'Yes' if is_public_filter(filter_data) else 'No',

filter_data.get('favourite', False),

filter_data.get('description', ''),

filter_data.get('viewUrl', '')

])

print(f"\nFilters exported to {filename}")

except Exception as e:

print(f"Error exporting to CSV: {e}", file=sys.stderr)

def main():

"""

Main function to execute the script.

"""

print("Jira Filters Listing Tool")

print("=" * 80)

# Validate credentials are configured

if JIRA_URL == "https://your-domain.atlassian.net" or \

JIRA_EMAIL == "your-email@example.com" or \

JIRA_API_TOKEN == "your-api-token-here":

print("\nERROR: Please update the configuration variables at the top of the script:")

print(" - JIRA_URL")

print(" - JIRA_EMAIL")

print(" - JIRA_API_TOKEN")

sys.exit(1)

# Create authentication

auth = HTTPBasicAuth(JIRA_EMAIL, JIRA_API_TOKEN)

# Fetch all filters

print("\nFetching filters...")

filters = get_all_filters(JIRA_URL, auth)

# Sort filters by name

filters.sort(key=lambda x: x.get('name', '').lower())

# Display options

print(f"\nFound {len(filters)} filters.")

print("\nDisplay options:")

print("1. Table view (summary)")

print("2. Detailed view")

print("3. Export to JSON")

print("4. Export to CSV")

print("5. All of the above")

choice = input("\nEnter your choice (1-5): ").strip()

if choice == '1' or choice == '5':

print_filters_table(filters)

if choice == '2' or choice == '5':

print_filters_detailed(filters)

if choice == '3' or choice == '5':

export_to_json(filters)

if choice == '4' or choice == '5':

export_to_csv(filters)

if choice not in ['1', '2', '3', '4', '5']:

print("Invalid choice. Showing table view by default.")

print_filters_table(filters)

if __name__ == "__main__":

main()

 

Adam Sterrie
January 20, 2026

Thank you. This looks great but I am being limited to using curl only  - no Python. Plus how do you get round the permission limitation on the API call "https://${JIRA_SITE}.atlassian.net/rest/api/3/filter/search" that does not return all filters?

Nikola Perisic
Community Champion
January 20, 2026

You need to be a Jira admin to see all of the filters. For Curl, you can try:

============================================================================
# CONFIGURATION - Update these variables with your Jira credentials
# ============================================================================
JIRA_URL="https://your-domain.atlassian.net" # Your Jira instance URL
JIRA_EMAIL="your-email@example.com" # Your Jira email address
JIRA_API_TOKEN="your-api-token-here" # Your Jira API token
# ============================================================================

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Function to check if required commands are available
check_requirements() {
local missing_tools=()

if ! command -v curl &> /dev/null; then
missing_tools+=("curl")
fi

if ! command -v jq &> /dev/null; then
missing_tools+=("jq")
fi

if [ ${#missing_tools[@]} -ne 0 ]; then
echo -e "${RED}Error: Missing required tools: ${missing_tools[*]}${NC}"
echo "Please install them:"
echo " - Ubuntu/Debian: sudo apt-get install curl jq"
echo " - MacOS: brew install curl jq"
echo " - RHEL/CentOS: sudo yum install curl jq"
exit 1
fi
}

# Function to validate configuration
validate_config() {
if [ "$JIRA_URL" = "https://your-domain.atlassian.net" ] || \
[ "$JIRA_EMAIL" = "your-email@example.com" ] || \
[ "$JIRA_API_TOKEN" = "your-api-token-here" ]; then
echo -e "${RED}ERROR: Please update the configuration variables at the top of the script:${NC}"
echo " - JIRA_URL"
echo " - JIRA_EMAIL"
echo " - JIRA_API_TOKEN"
exit 1
fi
}

# Function to fetch all filters with pagination
fetch_all_filters() {
local all_filters="[]"
local start_at=0
local max_results=50
local total=0
local is_last=false

echo -e "${BLUE}Fetching filters...${NC}"

while [ "$is_last" = "false" ]; do
# Make API request
response=$(curl -s -w "\n%{http_code}" \
-u "${JIRA_EMAIL}:${JIRA_API_TOKEN}" \
-H "Accept: application/json" \
"${JIRA_URL}/rest/api/3/filter/search?startAt=${start_at}&maxResults=${max_results}&expand=jql,owner,sharePermissions")

# Extract HTTP status code
http_code=$(echo "$response" | tail -n1)
body=$(echo "$response" | sed '$d')

# Check for errors
if [ "$http_code" != "200" ]; then
echo -e "${RED}Error: HTTP $http_code${NC}"
echo "$body" | jq -r '.errorMessages[]? // .message? // .'
exit 1
fi

# Get total count on first request
if [ $start_at -eq 0 ]; then
total=$(echo "$body" | jq -r '.total')
echo -e "${GREEN}Found $total filters${NC}"
fi

# Extract values and append to all_filters
current_filters=$(echo "$body" | jq -r '.values')
all_filters=$(echo "$all_filters" | jq --argjson new "$current_filters" '. + $new')

# Check if this is the last page
is_last=$(echo "$body" | jq -r '.isLast')

# Update start_at for next iteration
start_at=$((start_at + max_results))

# Progress indicator
fetched=$(echo "$all_filters" | jq 'length')
echo -ne "\rFetched: $fetched/$total filters"
done

echo # New line after progress
echo "$all_filters"
}

# Function to check if filter is public
is_public() {
local filter_json="$1"
echo "$filter_json" | jq -r '
if (.sharePermissions | any(.type == "global")) then
"Yes"
else
"No"
end
'
}

# Function to display filters in table format
display_table() {
local filters="$1"

echo ""
echo "==============================================================================================================="
printf "%-10s %-40s %-30s %-8s %-20s\n" "ID" "Name" "Owner" "Public" "Favorite"
echo "==============================================================================================================="

echo "$filters" | jq -r '.[] |
[
.id,
(.name | if length > 39 then .[0:36] + "..." else . end),
((.owner.displayName // "N/A") | if length > 29 then .[0:26] + "..." else . end),
(if (.sharePermissions | any(.type == "global")) then "Yes" else "No" end),
(if .favourite then "Yes" else "No" end)
] | @tsv' | \
while IFS=$'\t' read -r id name owner public favorite; do
printf "%-10s %-40s %-30s %-8s %-20s\n" "$id" "$name" "$owner" "$public" "$favorite"
done

total=$(echo "$filters" | jq 'length')
echo ""
echo "Total filters: $total"
echo ""
}

# Function to display detailed filter information
display_detailed() {
local filters="$1"

echo "$filters" | jq -r 'to_entries[] |
"
================================================================================
Filter #\(.key + 1)
================================================================================
ID: \(.value.id)
Name: \(.value.name)
Description: \(.value.description // "N/A")
Owner: \(.value.owner.displayName // "N/A") (\(.value.owner.emailAddress // "N/A"))
Email: \(.value.owner.emailAddress // "N/A")
JQL: \(.value.jql // "N/A")
Public: \(if (.value.sharePermissions | any(.type == "global")) then "Yes" else "No" end)
Favorite: \(if .value.favourite then "Yes" else "No" end)
View URL: \(.value.viewUrl // "N/A")
Search URL: \(.value.searchUrl // "N/A")
"'
}

# Function to export to JSON
export_json() {
local filters="$1"
local filename="${2:-jira_filters.json}"

echo "$filters" | jq '.' > "$filename"
echo -e "${GREEN}Filters exported to $filename${NC}"
}

# Function to export to CSV
export_csv() {
local filters="$1"
local filename="${2:-jira_filters.csv}"

# Write CSV header
echo "ID,Name,Owner Name,Owner Email,JQL,Public,Favorite,Description,View URL" > "$filename"

# Write data
echo "$filters" | jq -r '.[] |
[
.id,
.name,
(.owner.displayName // ""),
(.owner.emailAddress // ""),
(.jql // ""),
(if (.sharePermissions | any(.type == "global")) then "Yes" else "No" end),
(if .favourite then "Yes" else "No" end),
(.description // ""),
(.viewUrl // "")
] | @csv' >> "$filename"

echo -e "${GREEN}Filters exported to $filename${NC}"
}

# Function to export filters with full JQL to separate files
export_jql_files() {
local filters="$1"
local output_dir="${2:-jira_filters_jql}"

# Create output directory
mkdir -p "$output_dir"

# Export each filter's JQL to a separate file
echo "$filters" | jq -r '.[] |
"\(.id)|\(.name)|\(.jql // "")"' | \
while IFS='|' read -r id name jql; do
if [ -n "$jql" ]; then
# Sanitize filename
safe_name=$(echo "$name" | tr -cs '[:alnum:]-_' '_' | sed 's/_*$//')
filename="${output_dir}/${id}_${safe_name}.jql"
echo "$jql" > "$filename"
fi
done

total=$(find "$output_dir" -name "*.jql" 2>/dev/null | wc -l)
echo -e "${GREEN}Exported $total JQL files to $output_dir/${NC}"
}

# Main function
main() {
echo "================================================================================"
echo " Jira Filters Listing Tool "
echo "================================================================================"
echo ""

# Check requirements
check_requirements

# Validate configuration
validate_config

# Fetch all filters
filters=$(fetch_all_filters)

# Sort filters by name
filters=$(echo "$filters" | jq 'sort_by(.name | ascii_downcase)')

# Display menu
echo ""
echo "Display options:"
echo "1. Table view (summary)"
echo "2. Detailed view"
echo "3. Export to JSON"
echo "4. Export to CSV"
echo "5. Export JQL to separate files"
echo "6. All of the above"
echo ""
read -p "Enter your choice (1-6): " choice

case $choice in
1)
display_table "$filters"
;;
2)
display_detailed "$filters"
;;
3)
export_json "$filters"
;;
4)
export_csv "$filters"
;;
5)
export_jql_files "$filters"
;;
6)
display_table "$filters"
display_detailed "$filters"
export_json "$filters"
export_csv "$filters"
export_jql_files "$filters"
;;
*)
echo -e "${YELLOW}Invalid choice. Showing table view by default.${NC}"
display_table "$filters"
;;
esac
}

# Run main function
main
Adam Sterrie
January 20, 2026

Thanks again. I need to adapt to our environment and get back to you.

Like Nikola Perisic likes this
0 votes
Aaron Pavez _ServiceRocket_
Community Champion
January 20, 2026

Hi @Adam Sterrie 

You need to query the DB—no workaround for that. APIs won't give you the full view.

You can start here:

https://support.atlassian.com/jira/kb/jira-get-list-of-all-filters-shared-with-everyone/

Adam Sterrie
January 20, 2026

My site is in the cloud :( so no database access.

Suggest an answer

Log in or Sign up to answer
DEPLOYMENT TYPE
CLOUD
PRODUCT PLAN
ENTERPRISE
TAGS
AUG Leaders

Atlassian Community Events