publicdataau publicdata.au on GitHub
Published by Australian Taxation Office under CC BY 2.5 AU and republished here without change to the content. Australian Taxation Office has not endorsed this site.An independent republication of open government data. No government agency has endorsed it. Read more

Taxable income, salary, rent, tax and super by postcode, Australia, 2023-24

live
Publisher Australian Taxation OfficeUpdated yearlyLicence CC BY 2.5 AULatest 2026-06-12Rows 2,564Fields 34

Table 25 of the ATO's Taxation Statistics 2023-24 for individuals, selected items by postcode. Each row is one postcode, with the number of individuals who lodged and, for each item, the number with the item, the share with it where the ATO gives one, and its average and median in dollars.

Also called: Average income by postcode Australia, Median income by postcode ATO, ATO taxation statistics postcode data, Taxation statistics individuals table 25.

Before you use it
What is in each row?
One postcode, with the number of individuals who lodged a tax return for the 2023-24 income year and, for each of taxable income, salary and wages, net rent, total income, deductions, business income and expenses, net tax and super balances, the count of individuals with the item and its average and median in dollars. Some items also give the share of individuals with the item, as a fraction.
Which individuals are counted?
Counts, averages and medians for taxable income, total income and deductions use every individual, including zeroes. Net rent counts everyone who reported at the label. The other items count only individuals with a value other than zero. The figures come from 2024 returns processed by 31 October 2025 and are not necessarily complete.
Where are the other years?
The ATO publishes each income year as its own release with its own columns, so each year is its own table.

Made for agents

Connect your AI agent

Any agent that connects to publicdata.au/mcp can find this dataset, read its 34 fields, count and filter across all 2,564 rows and diff its versions. Every answer names the version and carries ATO's attribution. No key.

Then ask it: What does Taxable income, salary, rent, tax and super by postcode, Australia, 2023-24 hold, and what changed in the newest version?

claude mcp add --transport http publicdata https://publicdata.au/mcp

One command. No key, no account, no sign-up.

Download it as Excel, CSV, JSON and 6 more formats

Pick a format and a version. Excel is picked first because it opens in the tools most offices have. The URL is yours to keep. A dated version never changes.

Format
"Latest" redirects to the newest version and will change when the publisher releases again. A dated version never changes.
https://publicdata.au/d/au-taxable-income-by-postcode-2023-24/latest/data.xlsx
Download

In your own tools

Use it in Excel, R, Python and more

Excel and Power BI read the CSV from its address and refresh from it. The R and Python packages take any dataset on this site by its slug, so a new dataset needs no new release. The DuckDB file attaches read-only over HTTPS, and a query reads only the blocks it touches.

The dated URL in the code never changes. https://publicdata.au/d/au-taxable-income-by-postcode-2023-24/latest/ redirects to the newest version.

https://publicdata.au/d/au-taxable-income-by-postcode-2023-24/latest/data.csv

In Excel choose Data, then From Web, and paste this address. Excel keeps it, so Refresh All reads the newest version. A sheet holds about a million rows; past that, load the query to the Data Model.

What is in it

Column names are made snake_case and the publisher's original header is kept beside each one. Blank cells are null. Nothing is added, removed, ranked or summarised.

FieldTypePublisher's headerNote
postcodeintegerPostcodeThe postcode as the ATO publishes it, as a number, so Northern Territory postcodes such as 0800 appear as 800.
individualsintegerIndividuals no.
count_taxable_income_or_lossintegerTaxable income or loss no.
average_taxable_income_or_loss_audintegerAverage taxable income or loss $
median_taxable_income_or_loss_audintegerMedian taxable income or loss $
proportion_salary_or_wagesnumberProportion with salary or wages
count_salary_or_wagesintegerSalary or wages no.
average_salary_or_wages_audintegerAverage salary or wages $
median_salary_or_wages_audintegerMedian salary or wages $
count_net_rentintegerNet rent no.
proportion_net_rentnumberProportion with net rent
average_net_rent_audintegerAverage net rent $
median_net_rent_audintegerMedian net rent $
count_total_income_or_lossintegerTotal income or loss no.
average_total_income_or_loss_audintegerAverage total income or loss $
median_total_income_or_loss_audintegerMedian total income or loss $
count_total_deductionsintegerTotal deductions no.
average_total_deductions_audintegerAverage total deductions $
median_total_deductions_audintegerMedian total deductions $
count_total_business_incomeintegerTotal business income no.
proportion_total_business_incomenumberProportion with total business income
average_total_business_income_audintegerAverage total business income $
median_total_business_income_audintegerMedian total business income $
count_total_business_expensesintegerTotal business expenses no.
proportion_total_business_expensesnumberProportion with total business expenses
average_total_business_expenses_audintegerAverage total business expenses $
median_total_business_expenses_audintegerMedian total business expenses $
count_net_taxintegerNet tax no.
proportion_net_taxnumberProportion with net tax
average_net_tax_audintegerAverage net tax $
median_net_tax_audintegerMedian net tax $
count_super_total_accounts_balanceintegerSuper total accounts balance no.
average_super_total_accounts_balance_audintegerAverage super total accounts balance $
median_super_total_accounts_balance_audintegerMedian super total accounts balance $

Download this table as a data dictionary (Excel), or read it as a Frictionless Table Schema at schema.json. The key is postcode.

A sample of 10 rows

The postcodes with the most individuals lodging a return, most first. A blank cell is shown as null.

postcodeindividualscount_taxable_income_or_lossaverage_taxable_income_or_loss_audmedian_taxable_income_or_loss_audproportion_salary_or_wagescount_salary_or_wagesaverage_salary_or_wages_audmedian_salary_or_wages_audcount_net_rentproportion_net_rentaverage_net_rent_audmedian_net_rent_audcount_total_income_or_lossaverage_total_income_or_loss_audmedian_total_income_or_loss_audcount_total_deductionsaverage_total_deductions_audmedian_total_deductions_audcount_total_business_incomeproportion_total_business_incomeaverage_total_business_income_audmedian_total_business_income_audcount_total_business_expensesproportion_total_business_expensesaverage_total_business_expenses_audmedian_total_business_expenses_audcount_net_taxproportion_net_taxaverage_net_tax_audmedian_net_tax_audcount_super_total_accounts_balanceaverage_super_total_accounts_balance_audmedian_super_total_accounts_balance_aud
3029962209622060836520040.82787256765261608124050.13-9168-75969622063690550149622028341149178760.194667927125165220.173016712783758580.791637612142961277817828718
3030786617866173383615270.84657007861269642131510.17-8339-6860786617672264831786613300128682450.1784912550576650.15933210822637470.8121630156638356612213948492
3977742217422164247571570.8462440681816343983730.11-7374-6193742216729660014742213017111597710.13579043120992400.123508212895609710.8216934131017835310216946249
3064741177411759633522190.8260464657756103382950.11-8137-69597411762418550237411727521154125600.175554628706117790.163760913069584070.791575512170732557264429256
4350714767147671246572990.8158143699176252672040.11180071476750626050571476368294261080.09811862506658120.084987111280570940.821225137427827018965566527
2170625476254763843552140.8351893681906281085350.14-2750-2702625476681858165625472949111869350.11780723200064910.15719515052492980.7917726133166716210158236722
4740583015830184174686830.8650333845837298255840.1-15-272583018795972197583013689123034750.061078433159233580.067510214600488770.8425378181896487518336880701
2145552275522772837609630.8446642780266990894960.17-5079-4399552277591464287552273031124863930.121166102431059260.1110172210954445600.8121390156175841611511040231
2155521995219992376745920.85443519609383687130160.25-8166-6228521999598578160521993557132244900.091011372705842040.087429811192431780.8330097214205407716246878879
4209508755087568510582330.8543437689236271937980.07-2443-2083508757185561145508753255113055740.11568722881052570.13333911652417950.821901813366536279561037946
The first row as JSON

As it appears in data.json.

GET https://publicdata.au/d/au-taxable-income-by-postcode-2023-24/latest/data.json
{
  "postcode": 800,
  "individuals": 5907,
  "count_taxable_income_or_loss": 5907,
  "average_taxable_income_or_loss_aud": 74573,
  "median_taxable_income_or_loss_aud": 63390,
  "proportion_salary_or_wages": 0.91,
  "count_salary_or_wages": 5348,
  "average_salary_or_wages_aud": 73430,
  "median_salary_or_wages_aud": 66907,
  "count_net_rent": 724,
  "proportion_net_rent": 0.12,
  "average_net_rent_aud": -2506,
  "median_net_rent_aud": -1901,
  "count_total_income_or_loss": 5907,
  "average_total_income_or_loss_aud": 78222,
  "median_total_income_or_loss_aud": 66734,
  "count_total_deductions": 5907,
  "average_total_deductions_aud": 3630,
  "median_total_deductions_aud": 1584,
  "count_total_business_income": 560,
  "proportion_total_business_income": 0.09,
  "average_total_business_income_aud": 45776,
  "median_total_business_income_aud": 16318,
  "count_total_business_expenses": 518,
  "proportion_total_business_expenses": 0.09,
  "average_total_business_expenses_aud": 30823,
  "median_total_business_expenses_aud": 7180,
  "count_net_tax": 5202,
  "proportion_net_tax": 0.88,
  "average_net_tax_aud": 19663,
  "median_net_tax_aud": 13867,
  "count_super_total_accounts_balance": 6759,
  "average_super_total_accounts_balance_aud": 115076,
  "median_super_total_accounts_balance_aud": 23927
}

Query it without downloading

The query API returns only the rows you ask for, as JSON, NDJSON or CSV, from the same typed rows as the files. It needs no key. Build a query here and run it, then copy the URL or the code into your own work.

Try rows or aggregate for this dataset. The query builder needs JavaScript.

How filters work

Each filter is field=operator.value in the query string, and every filter must match. A number or date field compares as a number or date, and a text field compares as text. Values are case-sensitive except with ilike. Prefix not. to negate a filter, as not.eq.value.

OperatorWhat it matches
eq.valueEqual to the value.
neq.valueNot equal to the value. A blank cell does not match.
gt.valueGreater than the value.
gte.valueGreater than or equal to the value.
lt.valueLess than the value.
lte.valueLess than or equal to the value.
like.*text*Matches a pattern where * stands for any run of characters. Case-sensitive.
ilike.*text*The same as like, ignoring case.
in.(a,b,c)Equal to any value in the list. A value cannot contain a comma.
is.nullBlank in the source, or suppressed by the publisher.
ParameterWhat it does
selectFields to return, comma-separated. Every field when absent.
orderfield.asc or field.desc, comma-separated. The publisher's row order when absent.
limitRows per page, 1 to 10,000. 100 when absent.
offsetRows to skip. The next URL in each answer sets it for you.
groupOn aggregate, fields to group by, comma-separated.
metricOn aggregate, count, sum.field, avg.field, min.field or max.field, comma-separated. count when absent.
formatjson, ndjson or csv. JSON carries the provenance header, and the others carry it in response headers.

Without a version the API answers from the newest loaded version, and that answer changes when the publisher releases again. Put versions/<date>/ before rows or aggregate for an answer that never changes. /api/v1/datasets/<slug>/versions lists the loaded versions. The 1 newest version is loaded; versions lists them.

The API allows 60 requests in 10 seconds from one address. Above that it answers 429 for 10 seconds with a Retry-After header, a RateLimit-Policy header and a JSON body that gives the limit. Every API answer carries the same RateLimit-Policy. A client should wait the Retry-After seconds, or read the files, which have no limit. openapi.json describes this dataset's query paths for client generators and agents.

https://publicdata.au/mcp is a remote MCP server over Streamable HTTP with the same tools, defined in the same place, so a tool added to the pages is added here too. It needs no key and no account. The row tools are held to the query API's limit of 60 queries in 10 seconds from one address, and each call is two queries because it also counts the matching rows. Add it to Claude Code with claude mcp add --transport http publicdata https://publicdata.au/mcp, add the URL in Claude as a custom connector, or give it to any client that connects to remote MCP servers. Each queryable dataset is also a resource at https://publicdata.au/d/<slug>/fields.json, which lists its fields with their types, the publisher's descriptions, their ranges and the values they hold, so an agent can read a dataset's shape before it writes a query.

What changed

One version for every release the publisher has made since this site started following the dataset. The date is the day the file changed on the portal.

versions.json · changes.json · history.tar.zst (191 KB, every version's Parquet and manifest)

Questions

How do I download Taxable income, salary, rent, tax and super by postcode, Australia as a CSV file?

Open https://publicdata.au/d/au-taxable-income-by-postcode-2023-24/latest/data.csv. It redirects to the newest dated version, which is https://publicdata.au/d/au-taxable-income-by-postcode-2023-24/v/2026-06-12/data.csv today. The same path serves Excel, JSON, Parquet, SQLite, DuckDB, NDJSON, Arrow. A dated URL never changes, so use it when the file must stay the same.

Can I open Taxable income, salary, rent, tax and super by postcode, Australia in Excel?

Yes. https://publicdata.au/d/au-taxable-income-by-postcode-2023-24/v/2026-06-12/data.xlsx is a workbook with the 2,564 rows on a records sheet, the field list on a second sheet and the provenance on a third. The CSV also opens in Excel. https://publicdata.au/d/au-taxable-income-by-postcode-2023-24/v/2026-06-12/data.csv.gz is the CSV at about a tenth of the size.

What years does Taxable income, salary, rent, tax and super by postcode, Australia cover?

The current version covers the years since 2023. Each release from ATO becomes a new dated version here, and earlier versions stay online.

How often is Taxable income, salary, rent, tax and super by postcode, Australia updated?

ATO releases it yearly. This site checks the portal every week and adds a dated version when the file changes.

Can I use Taxable income, salary, rent, tax and super by postcode, Australia commercially?

Yes. CC BY 2.5 AU allows commercial use, redistribution and derived works as long as the attribution is kept. The attribution string is in this page's side column and inside every file.

Is this the official source for Taxable income, salary, rent, tax and super by postcode, Australia?

No. The publisher is Australian Taxation Office, and its page is https://data.gov.au/data/dataset/taxation-statistics-2023-24. This site republishes the publisher's file without changing its content. The original sits beside every version as source.xlsx with its SHA-256, so the two can be compared.

What this site did to the data. Cells were typed, headers were renamed and the encoding was made UTF-8. Rows were left alone. The publisher's file sits beside every version as source.xlsx so the change can be checked.