Webperf's API
The API is under constant change – Work in Progress
More information and documentation is added continuously. Unless stated otherwise, responses are in JSON format. Want to see the OpenAPI/Swagger documentation? You'll find it here!
1. Open data
The data that Webperf releases as open data is published under the CC BY-SA 4.0 licence. This means you need to give proper attribution (that the data source is Webperf), and if you share the data source further, or adapt it, it must keep the same licence.
1.1 URLs to municipality and region websites
The URLs you get from this API endpoint are the addresses of municipality and region websites as stored
at Webperf.se. Usually that is the start page, but a few municipalities use a sub-page as the entry point
for residents, and then that is the address given here.
Note that Visby municipality in this list has been replaced by Region Gotland.
GET
https://api.webperf.se/public-sector/
The response contains the following data:
- api_version a version number (decimal) that tells you which version of the API you reached. Useful as a reference if you save the result.
- result_count the number of unique websites in the list of data (an integer).
- timestamp date and time when the response was created, in Swedish time with offset (for example 2026-10-11 21:09:21.423482+02:00). The response may be cached for up to 5 minutes, so the time can be a few minutes older than your call.
- data a list of websites, containing the following data:
- category a string that is either Municipality, i.e. a municipality, or Region if it is a region.
- id the website's id number (integer), the same as in /v1/.
- title a string with the name of the organisation.
- website a string with the website's address, usually the start page.
- same_as a URI (string) referencing the same organisation on Wikidata.
- uri a string referencing the organisation on Webperf. Work in progress. URLs to Webperf-internal content will be added in time.
- url and sameAs are older names for website and same_as, with the same values. They remain for existing integrations.
The point of URIs to Wikidata? Linked data!
"Linked data is a method of publishing structured data in a way that makes it possible to follow connections between pieces of information across multiple sources. Linked data builds on web standards such as HTTP and URIs, but instead of using them to present information to humans, the aim is to make data readable by machines. The goal is to enable widely differing actors to describe their information in a uniform way and thereby simplify reuse and interoperability."
So you can relate information at Webperf with Wikidata, which lets you fetch both even more data and also connect to various Wikipedia articles you may want to work with. This makes the data source machine-readable and processable automatically in your own application.
This can be handy if you want to automate fetching municipalities' names in other languages, which province they belong to, population size, their official email address, images from Wikimedia and everything else offered by Wikidata. See, for example, Wikidata's URI for Åmål municipality.
Code examples to get you started with Webperf's open data
On Webperf's GitHub account there are code examples you can reuse or take inspiration from.
- 01 - Code example for api.webperf.se fetches municipalities and regions from Webperf, connects to each website, looks at the page titles, and fetches population data from Wikidata.
1.2 Persistent URI (for municipalities and regions)
A URI is an identifier in the (linked) open data world. It is meant to be persistent and a unique
reference that you may come across in datasets from Webperf. External parties are also free to use
these URIs.
You'll find URIs in each listing and they can also be looked up. A URI for Webperf follows the syntax below and returns the public information that is available to share.
Do you have Premium? Then you can get your own data and the overall scores just by supplying an API key. See more about URIs for Premium.
GET
https://api.webperf.se/item/number
For example the following for Västra Götaland Region:
GET
https://api.webperf.se/item/141
The response contains the following data:
- api_version a version number (decimal) that tells you which version of the API you reached. Useful as a reference if you save the result.
- timestamp date and time when the response was created, in Swedish time with offset. The response may be cached for up to 10 minutes.
- data lists information about the website:
- category a string that is either Municipality, i.e. a municipality, or Region if it is a region.
- id the website's id number (integer), the same as in /v1/.
- title a string with the name of the organisation.
- website a string with the website's address, usually the start page.
- same_as a URI (string) referencing the same organisation on Wikidata.
- uri a string referencing the organisation on Webperf. Work in progress. URLs to Webperf-internal content will be added in time.
- url and sameAs are older names for website and same_as, with the same values. They remain for existing integrations.
1.3 Test types
In several of the API's responses a field type_of_test appears – an integer that identifies which kind of test was run. This endpoint is an open catalogue of every test type in Webperf Core, with their id numbers and names. So you need no API key. The data source is Webperf Core and is released as open data.
Note that the names of the test types that are active in the current Webperf Core are taken verbatim from Webperf Core's own locale files. Descriptions, and names for historical (inactive) tests in Danish, Norwegian, Finnish and Icelandic, are machine-translated from Swedish/English and should be reviewed before you fully rely on them.
Fetch the whole list:
GET
https://api.webperf.se/v1/tests
Or a single test type by its id number:
GET
https://api.webperf.se/v1/tests/number
For example the following for the performance test (Sitespeed.io):
GET
https://api.webperf.se/v1/tests/15
There are two optional query parameters:
- lang flattens the response to a single language. Allowed values are sv, en, da, no, fi and is. If you omit it you get all languages gathered under the translations node. If you supply an unsupported language you get status code 400.
- active with the value 1, true or yes gives you only the test types in active use. List endpoint only.
Example with English names and active tests only:
GET
https://api.webperf.se/v1/tests?lang=en&active=true
The response contains the following data:
- count integer for how many test types are in the list of data.
- meta metadata about the data source: language shows which language the response applies to (or all if you didn't pick one), catalogue_size is the number of test types that have ever existed (retired ones included, so old type_of_test values can still be looked up) and active_count the number in the current suite. count above is what your particular call returned.
- tests a list of test types (or test with a single object when you fetch by
id number), containing the following data:
- id integer that identifies the test type. This is the same number you see in type_of_test in other API responses.
- active a boolean that indicates whether the test type is in active use.
- url_with_details a string with a URL to more information about the test on Webperf.se (may be empty).
- name, description and long_description strings with name and descriptions. These sit directly on the object if you supplied lang.
- translations appears instead if you did not supply lang, and has a node per language (sv, en, da, no, fi, is) with their respective name, description and long_description.
The response is delivered with long cache headers and an ETag, so a conditional request with If-None-Match can return status code 304 (Not Modified) and save bandwidth.
1.4 More open endpoints
Beyond those above there are some newer open endpoints. They return the same municipalities and regions as 1.1, with the same id numbers, but in a more modern format with the ratings included, pagination and search. All respond with JSON and need no key.
GET https://api.webperf.se/v1/public/municipalitiesreturns every municipality in the list municipalities. Each entry has id, title, website, same_as and ratings. name is an older name for title and remains. The response also has count and meta, where last_updated is the most recent day (YYYY-MM-DD) on which any municipality in the list got new ratings.GET https://api.webperf.se/v1/public/regionsreturns the same for regions, in the list regions.GET https://api.webperf.se/v1/public/statsreturns the number of websites and the average of each of the five ratings across all municipalities and regions. Missing ratings are left out. meta.generated_at is the time of the call in UTC.GET https://api.webperf.se/v1/sites?query=text&category=2|3&limit=25&offset=0searches municipalities (category 2) and regions (category 3) by name or address. Each entry has id, title, website, category, category_name, same_as and api_url, but no ratings. Without limit you get 10 per page, and at most 100. The response has pagination with total and has_more.GET https://api.webperf.se/v1/sites/numberreturns a single municipality or region with the same fields as the search (except api_url) plus ratings, date_added, last_updated and recent_tests, the number of current tests. The dates are in Swedish time with offset, for example 2026-10-10T21:15:16+02:00. Websites that are not open municipalities or regions answer 403.GET https://api.webperf.se/datasets/dcatreturns the datasets described as DCAT-AP (RDF/XML), for Sweden's data portal.GET https://api.webperf.se/healthandGET https://api.webperf.se/inforeturn operational status and a short description of the API, respectively.
ratings has overall, accessibility, performance, standards and security as decimals between 1 and 5. A rating is null when the website has no rating for that area.
Every open endpoint uses the names id, title, website and same_as. Some of them also keep an older name for the same value, so that existing integrations keep working. Prefer the common names in new code.
| Common name | Older name | Found in |
|---|---|---|
| title | name | /v1/public/ |
| website | url | /public-sector/ and /item/ |
| same_as | sameAs | /public-sector/ and /item/ |
Only open websites appear in the open endpoints. With Premium you reach your own websites with your API key even when they are not open, see 2.7.
2. Webperf's premium API
Quick links to the premium endpoints:
- 2.1 Fetch your latest scores
- 2.2 Historical scores
- 2.3 Re-test the start page
- 2.4 Start private tests
- 2.5 Fetch a list of your private tests
- 2.6 Fetch test results for one of your private tests
- 2.7 Your own URI gives you your latest overall scores
- 2.8 Get a text's readability index (LIX)
- 2.9 The categories' average scores
- 2.10 Trigger a Premium Audit
- 2.11 Fetch your Premium Audits or reviews
- 2.12 Remaining credits in your quota
Only for you with Webperf Cloud on the Standard or Agency plan. You need to fetch your
API key via your account to get started. If you don't have your API key yet, log in to premium.webperf.se and click API key in the menu to create one.
Read more about Webperf's different plans »
Good to know about numbers. Every endpoint delivers numbers as numbers. Counts and id numbers are integers, for example "result_count": 17, and scores are decimals, for example "rating": 4.92. A missing score is null. Up to version 1.0.5 the older endpoints (the ones under /0.1/ and without a prefix) delivered numbers as strings and missing scores as "-1", see the version history.
Rate limits. Limits are counted per endpoint and per IP address, for the open endpoints as well as for premium. The older endpoints (without a prefix and under /0.1/) allow 100 calls per hour unless stated otherwise, and some have their own, lower limits. The open /v1/ endpoints allow between 60 and 120 calls per minute. Every response carries the headers X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset and Retry-After, also when all is well. X-RateLimit-Limit is the limit that applies to that particular call and Retry-After is the number of seconds until the counter resets. Exceeding the limit gives status code 429.
The premium APIs are versioned so that you can trust that your integrations won't suddenly
break. Each version is supported for at least 6 months, and it may become longer as the API is released in
newer versions going forward.
You don't have to pick a version in your calls, but if you do, it's an extra path segment with a decimal number in the API endpoints below. If you don't pick a versioned endpoint you always get the latest version.
If you don't have premium but want to try it out, you can use the demo account that exists for Webperf.se as a site. In that case it's API key 989089bfe899d6992ff320a97 and the site's id number 3843 that you use.
Looking for code examples to work with the premium API?
There are code examples in Python at the link below. It runs in Jupyter Notebook, which is also compatible with Google Colab as an environment if you prefer that.
With the code example you can interact with the premium API by asking which id number your website has, fetch the latest results, historical average scores and create a graph of the average scores over time.
These are just code examples. To give inspiration for what you can do to get started with the premium API. There are surely other automations and integrations you'll think of.
- 02 - Code example for the premium API (GitHub, updated 2023-07-24)
2.1 Fetch your latest scores
Here you get, in JSON format, the same tests you can see on Webperf.se as test results.
Initially you may not know which id number your website has. Then you can make the API request below together with your API key, and you'll find out which id numbers you have access to. This is also shown on the Info page if you log in to premium.
GET
https://api.webperf.se/stats/
https://api.webperf.se/0.1/stats/
HTTP header
Key: api-key
Value: your-api-key
The response has a list sites where each website has site-ID (the id number, an integer), title and website (name and address), uri (your URI as in 2.7) plus endpoint-current-stats and endpoint-historic-stats with ready-made addresses for 2.1 and 2.2. If the key is missing or invalid, this particular listing answers with status code 400; the per-website endpoints answer 401.
If you only want to check that the key works, for instance in a CI job, there is a cheaper call that lists no websites and never includes the key itself in the response:
GET
https://api.webperf.se/whoami/
https://api.webperf.se/0.1/whoami/
HTTP header
Key: api-key
Value: your-api-key
The response contains user_id, display_name, role (user, agency_admin or super_admin), site_count (the number of websites the key reaches) and unrestricted (true for super admins). A missing or invalid key gives 401.
Once you know the website's id number, your API endpoint is the following to get statistics:
GET
https://api.webperf.se/stats/number
https://api.webperf.se/0.1/stats/number
HTTP header
Key: api-key
Value: your-api-key
There are two optional query parameters:
- type_of_test narrows the response to certain tests, comma-separated, for example ?type_of_test=10,15. The id numbers are listed in 1.3 Test types. An invalid value gives status code 400.
- include_raw_data with the value false omits the field json_check_data, which can be hundreds of kB per test. It is included by default.
It might look like this if you use Webperf.se's demo account:
GET
https://api.webperf.se/stats/3843
HTTP header
Key: api-key
Value: 989089bfe899d6992ff320a97
The response contains the following data:
- api_version a version number (decimal) that tells you which version of the API you reached. Useful as a reference if you save the result.
- uri a string referencing which website on Webperf the test results belong to.
- result_count the number of unique tests in the list of data (an integer).
- timestamp date and time when the response was created, in Swedish time with offset.
- data lists the latest test results:
- type_of_test identifies the type of test performed (an integer, for example 10).
- rating the score for the current test (a decimal, for example 4.92, or null when there is no score).
- test_date timestamp for when the test was carried out, in Swedish time with offset.
- check_report a string with the main test result, in readable form.
- check_report_a11y a string with the test result concerning accessibility, in readable form.
- check_report_perf a string with the test result within web performance, in readable form.
- check_report_sec a string with the test result for information security, in readable form.
- check_report_stand a string with the test result regarding web standards, in readable form.
- json_check_data a JSON-formatted string with the test result. Used in a few test types. Can be very large; see include_raw_data above.
2.2 Historical scores
Webperf has collected test results for many years for certain websites. For example monthly for all municipalities since the summer of 2018. All scores are part of a kind of "category score", which is what you see reported in the recurring monthly reports on Webperf.se, but it can be tedious to compile your own data from those reports. That's why this API endpoint exists.
GET
https://api.webperf.se/stats_per_month/number
https://api.webperf.se/0.1/stats_per_month/number
HTTP header
Key: api-key
Value: your-api-key
It might look like this if you use Webperf.se's demo account:
GET
https://api.webperf.se/stats_per_month/3843
HTTP header
Key: api-key
Value: 989089bfe899d6992ff320a97
The response contains the following data:
- api_version a version number (decimal) that tells you which version of the API you reached. Useful as a reference if you save the result.
- uri a string referencing which website on Webperf the test results belong to.
- result_count the number of unique monthly scores in the list of data (an integer). Not to be confused with the number of months. One and the same month can have a handful of different scores in your result. See type_of_score below.
- timestamp date and time when the response was created, in Swedish time with offset.
- data lists the average scores of all test results:
- score the average score for the current month and the tests included in that type of test (a decimal). See type_of_score.
- timeperiod a date in the format yyyy-mm and is within the period the tests were carried out.
- type_of_score a string that identifies which type of tests were summed up into an average score for the month. The options are fairly self-explanatory; kat-total total score for all tests, kat-infosec for information security/privacy, kat-a11y for accessibility, kat-perf for everything within web performance and kat-webstandard for compliance with web standards.
2.3 Re-test the start page
Do you want to manually re-run the tests of your website so that Webperf.se takes a fresh look? The test applies to the start page of your website and the result will be published on Webperf.se when the test is done, and you can reach the new tests via the API through 2.1 Fetch your latest scores.
You have a limited number of credits in a rolling 30-day period. Each test costs 1 credit. If the whole order doesn't fit in what you have left it is refused with status code 400 – 2.12 Remaining credits in your quota tells you what is left before you order.
The number you supply is the website's id number. If you don't know your website's id number, run the API request under 2.1 Fetch your latest scores and you'll get it in the response.
POST
https://api.webperf.se/retest/
https://api.webperf.se/0.1/retest/
HTTP header
Key: api-key
Value: your-api-key
Key: site-id
Value: number
Optional – if you only want to run certain tests:
Key: testnums
Value: [1, 10, 15]
Without testnums every active test is queued, 1 credit per test. The allowed id numbers are the ones that are active in 1.3 Test types (/v1/tests?active=true). Unknown or inactive ids are silently ignored; if no valid id remains the API answers 400 with No valid test numbers provided.
It might look like this if you use Webperf.se's demo account:
POST
https://api.webperf.se/retest/
HTTP header
Key: api-key
Value: 989089bfe899d6992ff320a97
Key: site-id
Value: 3843
The response to your POST is status code 200 if it went well and {"message": "Website with site-id 3843 will be retested in a couple of minutes"}. Error cases: 400 if site-id or api-key is missing or invalid, 403 if the key does not reach the website, 404 if the website does not exist, 400 with Quota exceeded if the credits do not suffice, and 500 if something went wrong on the server side.
2.4 Start private tests
You can test up to 10 sub-pages of your choice per call to the API. The number of pages you can test is governed by which level of premium your website has. If you have one of the larger premium variants you have room to make several API posts in a row and then wait for the test results to come in over the 15-30 minutes it usually can take.
See 2.5 Fetch a list of your private tests for how, via the API, you get the API calls you make to reach these private tests.
You have a limited number of credits in a rolling 30-day period. Each page tested costs 15 credits – the same price as in the web interface at webperf.cloud. If the whole order doesn't fit in what you have left it is refused with status code 400 – 2.12 Remaining credits in your quota tells you what is left before you order.
POST
https://api.webperf.se/test_once/
https://api.webperf.se/0.1/test_once/
HTTP header
Key: api-key
Value: your-api-key
Key: site-id
Value: number
HTTP body (form-data)
Key: urls
Value: url1
or
Value: url1, url2, url3 – url10
The body is sent as form-data (application/x-www-form-urlencoded or multipart/form-data), not as JSON. Several addresses are separated by a comma followed by a space. Every address must be on the same domain as the website, otherwise the API answers 400.
It might look like this if you use Webperf.se's demo account:
POST
https://api.webperf.se/test_once/
https://api.webperf.se/0.1/test_once/
HTTP header
Key: api-key
Value: 989089bfe899d6992ff320a97
Key: site-id
Value: 3843
HTTP body
Key: urls
Value: https://webperf.se/articles/nyhetsbrev-38/, https://webperf.se/tag/tillganglighet/
The response to your POST is status code 200 if it went well, with the number of tests created and one address per test where the result can later be fetched as in 2.6:
{
"message": "Created 2 single tests for site-id 3843",
"endpoints": {
"7291": "https://api.webperf.se/private_stats/3843/7291",
"7292": "https://api.webperf.se/private_stats/3843/7292"
}
}
Status code 400 means something is missing or does not fit: no address given, an address outside the website's domain, or not enough credits (then the message starts with Quota exceeded and says how many are needed and how many remain in the rolling 30-day period).
2.5 Fetch a list of your private tests
These are called private tests because they are not openly accessible on Webperf.se or to other users of the API than those with the same permission as you.
With the API response below you get URIs to fetch all test results for a privately tested URL. This API URI requires you to supply your API key to get the response, see 2.6 Fetch test results for one of your private tests below.
GET
https://api.webperf.se/private_stats/number
https://api.webperf.se/0.1/private_stats/number
HTTP header
Key: api-key
Value: your-api-key
It might look like this if you use Webperf.se's demo account:
GET
https://api.webperf.se/private_stats/3843
https://api.webperf.se/0.1/private_stats/3843
HTTP header
Key: api-key
Value: 989089bfe899d6992ff320a97
The response contains the following data:
- api_version a version number (decimal) that tells you which version of the API you reached. Useful as a reference if you save the result.
- uri a string referencing which website on Webperf the test results belong to.
- result_count the number of different URLs tested (an integer).
- timestamp date and time when the response was created, in Swedish time with offset.
- data lists all URLs:
- date_added ISO date (yyyy-mm-dd hh:mm:ss) for when the test was requested.
- uri the API address to call to reach the test details.
- url is the address that was evaluated in the tests.
2.6 Fetch test results for one of your private tests
Only those with API access to the website at Webperf or logged in to Premium can access these results. They are not shared openly.
GET
https://api.webperf.se/private_stats/number/test_id
https://api.webperf.se/0.1/private_stats/number/test_id
HTTP header
Key: api-key
Value: your-api-key
It might look like this if you use Webperf.se's demo account:
GET
https://api.webperf.se/private_stats/3843/7289
https://api.webperf.se/0.1/private_stats/3843/7289
HTTP header
Key: api-key
Value: 989089bfe899d6992ff320a97
The response has the same frame as 2.1 Fetch your latest scores (api_version, uri, result_count, timestamp and data), but each entry in data has only four fields: test_date, type_of_test, rating and check_report. The per-area reports and json_check_data do not exist for private tests. A test that has not run yet gives an empty data list and result_count 0.
2.7 Your own URI gives you your latest overall scores
This endpoint has some similarities with 1.2 Persistent URI (for municipalities and regions), but with the difference that it applies to your own website. You also get a bit more data because you supply your API key.
Note! Mind the hyphen in api-key in this particular code example. Without a key, a website that is not a municipality or region answers 404.
GET
https://api.webperf.se/item/number
For example the following for Webperf's demo account:
GET
https://api.webperf.se/item/3843
HTTP header
Key: api-key
Value: 989089bfe899d6992ff320a97
The response contains the following data:
- api_version a version number (decimal) that tells you which version of the API you reached. Useful as a reference if you save the result.
- timestamp date and time when the response was created, in Swedish time with offset.
- data lists information about the website:
- category a string that is Municipality for a municipality, Region for a region and Unknown for every other website, for example your own.
- id the website's id number (integer), the same as in /v1/.
- title a string with the name of the organisation.
- website a string with the website's address, usually the start page.
- same_as a URI (string) referencing the same organisation on Wikidata. Empty for websites without a Wikidata link.
- uri a string referencing the organisation on Webperf. Work in progress. URLs to Webperf-internal content will be added in time.
- url and sameAs are older names for website and same_as, with the same values. They remain for existing integrations.
- scores lists the overall scores for the web page, all as decimals (null when there is no score):
- a11y two decimals, summarises the page's accessibility
- infosec two decimals, summarises the page's information security and privacy
- overall five decimals, the overall score
- pagespeed two decimals, the page's speed
- webstandard two decimals, the page's compliance with web standards
So the response is the same as in 1.2 Persistent URI, complemented with the scores node. If you send a key that does not reach the website you get the public variant without scores for municipalities and regions, and 404 for other websites.
2.8 Get a text's readability index (LIX)
A text can be more or less easy to read. LIX is a measure of this and you, with the premium API, can easily check your texts via the API. Sooner or later LIX calculation will be included in the quota system with test credits.
POST
https://api.webperf.se/tools/lix/
HTTP header
Key: api-key
Value: your-api-key
Key: site-id
Value: your-site-id-number
HTTP body (form-data)
Key: content
Value: your text to readability-test, at least 50 words
The endpoint exists only without a version prefix and only takes POST. The text is sent as form-data, not as JSON. The response data sits under message:
- lix_value integer with the LIX value.
- interpretation a string (in Swedish) about how easy or hard the text is to read.
- stats what was counted: words, sentences, long_words, avg_sentence_length and long_word_percentage.
It might look like this:
{
"message": {
"lix_value": 52,
"interpretation": "Svår, normalt värde för officiella texter",
"stats": {
"words": 312,
"sentences": 14,
"long_words": 94,
"avg_sentence_length": 22.29,
"long_word_percentage": 30.13
}
}
}
Texts under 50 words give status code 400 with {"message": "Text must contain at least 50 words"}. If content is missing altogether it is 400 with No content provided.
2.9 The categories' average scores
The categories of websites that appear on Webperf.se have average scores in each score category. These you can fetch in a structured way with the premium API.
GET
https://api.webperf.se/categories/
https://api.webperf.se/0.1/categories/
HTTP header
Key: api-key
Value: your-api-key
The response contains the following data:
- categories lists all categories:
- cat_id is the category's id number, as a reference (an integer).
- title name of the category.
- The scores below are decimals, null when there is no score.
- rating_a11y average accessibility score.
- rating_infosec average score for information security.
- rating_pagespeed average speed score.
- rating_webstandard average score for web standards.
- rating_overall average total score.
2.10 Trigger a Premium Audit
For you with a Premium account, you can trigger a Premium Audit via the API. The audit always starts from your website's start page and crawls its way to the pages it tests – you can't submit a list of URLs of your own choosing.
pages decides how many pages are crawled and tested, and costs 1 credit per page from your rolling 30-day quota. You can order at most one audit per hour.
POST
https://api.webperf.se/audit/
https://api.webperf.se/0.1/audit/
HTTP headers
Key: api-key
Value: your-api-key
Key: site-id
Value: your-site-id-number
Key: pages
Value: number of pages, for example 50
pages can also be sent as form-data under the same name, if that suits your client better.
The response contains the following data:
{
"message": "Audit for site-id nnnn will be processed in a couple of hours"
}
Or, if the order doesn't fit in your remaining credits, status code 400 and:
{
"message": "Quota exceeded. This audit needs 200 credits but only
40 remain for the current 30-day period."
}
2.11 Fetch your Premium Audits or reviews
If you have already run a Premium Audit or want to know whether the one you ordered is done yet, you can use this endpoint. Under data you may get an empty result if nothing is finished, a single result as in the example below, or more than one result.
Variants of format are csv for primarily automated accessibility tests, audit and audit_v2.
This is how the results work:
- csv – gives you a comma-separated text ready to be loaded into a spreadsheet or for processing with code. Has no result_files.
- audit – is, as in the example below, some metadata about a test result, and result_files gives you a list of JSON files. The content of the JSON files is what you would find from Google Lighthouse recently.
- audit_v2 – the same, plus two more files: crux_summary.json (Google CrUX data) and privacy_summary.json. Also summaries.zip, which holds every summary in one archive – one request instead of six.
POST
https://api.webperf.se/audits/
https://api.webperf.se/0.1/audits/
HTTP headers
Key: api-key
Value: your-api-key
Key: site-id
Value: your-site-id-number
The response looks as follows (if you have access):
{
"api_version": "0.1",
"data": [
{
"content": "{\"date\": \"YYYY-MM-DD\", \"folder\": \"/static/results/webbplats.se_yyyymmdd_hhmmss-summary_reports/\", \"base_url\": \"https://webbplats.se\"}",
"date_modified": "2025-05-12T22:20:01+02:00",
"format": "audit",
"result_files": [
"https://api.webperf.se/0.1/audit_file/?folder=webbplats.se-2025_05_12_18-results&file=accessibility_summary.json",
"https://api.webperf.se/0.1/audit_file/?folder=webbplats.se-2025_05_12_18-results&file=performance_summary.json",
"https://api.webperf.se/0.1/audit_file/?folder=webbplats.se-2025_05_12_18-results&file=seo_summary.json",
"https://api.webperf.se/0.1/audit_file/?folder=webbplats.se-2025_05_12_18-results&file=best-practices_summary.json"
],
"site_id": nnnn,
"result_id": nnn,
"title": "Audit Webbplats.se"
}
],
"result_count": 1,
"timestamp": "2025-05-28 21:43:02.311244+02:00"
}
site_id is the website's id number, the same one you sent in. result_id is the row's own id. content is a string holding JSON for newer rows; older rows hold a Python-dict string with single quotes instead, so parse the field tolerantly.
Fetching the report files
The files under result_files are not publicly readable. Each file is fetched with the same api-key and site-id as the listing, and the folder must belong to your website – a valid API key does not give you access to anyone else's reports. Call the URL as-is with your headers:
GET or POST
https://api.webperf.se/0.1/audit_file/?folder=folder-name&file=file-name
HTTP headers
Key: api-key
Value: your-api-key
Key: site-id
Value: your-site-id-number
For example with curl:
curl -H "api-key: your-api-key" -H "site-id: nnnn" \
"https://api.webperf.se/0.1/audit_file/?folder=webbplats.se-2025_05_12_18-results&file=seo_summary.json"
Responds 403 if the key lacks access to the website or the folder belongs to someone else, and 404 if the file does not exist. These files used to sit openly on premium.webperf.se/static/results/; those old links stop working.
2.12 Remaining credits in your quota
Orders cost credits: 1 per test in a re-test, 15 per privately tested page and 1 per page in an audit. This is where you see what you have left before you order, rather than finding out from an error message.
The quota is either set on your website directly or derived from its premium level. The period is a rolling 30 days – credits free up continuously, and there is no day of the month when everything resets.
GET
https://api.webperf.se/quota/
https://api.webperf.se/0.1/quota/
HTTP headers
Key: api-key
Value: your-api-key
Key: site-id
Value: your-site-id-number
The response contains the following data:
- site_id integer with the website's id number, the one you sent in.
- monthly_quota integer with the website's ceiling for the period.
- premium_active true or false. false when Webperf Cloud is deactivated or its end date has passed. Results and access remain, but nothing new can be ordered.
- premium_enddate end date (YYYY-MM-DD) for Webperf Cloud, or null.
- effective_limit integer with the ceiling that applies when ordering. Same as monthly_quota, or 0 when premium_active is false.
- used integer with the credits used over the last 30 days.
- available integer with the remaining credits. Never below 0.
- period_days integer with the length of the rolling window, i.e. 30.
It might look like this:
{
"api_version": "0.1",
"site_id": nnnn,
"premium_active": true,
"premium_enddate": "2027-03-31",
"monthly_quota": 1500,
"effective_limit": 1500,
"used": 460,
"available": 1040,
"period_days": 30,
"timestamp": "2026-08-06 09:12:44.102938+02:00"
}
No account type has an unlimited quota. A website with no premium level gets 0 all the way through and cannot order anything.
3. Premium for web agencies
As a web agency there is a special premium access. Part of it is that you can manage both your own website and your clients'. Another is that it gives you access to information that can make your sales work easier. What is exclusive to web agencies' premium is listed below.
3.1 Which web analytics tools are used on websites Webperf follows
This API requires that you have Premium for web agencies.
GET
https://api.webperf.se/webanalytics?api-key=API-key
The response you get from the API is a CSV file, separated by semicolons. For just under 4000 websites important to a digital Nordics, primarily Sweden.
What output do you get? Well:
- title – what is the website's name?
- url – which address was tested?
- test_date – when was the website last tested?
- ga_or_gtm – is Google Analytics or Google Tag Manager present in the code?
- vizzit – is the cloud service Vizzit found in the code?
- siteimprove_analytics – does the website have Siteimprove Analytics?
- matomo – does Matomo Analytics exist for web analytics?
- piwik_pro – does the website have Piwik PRO (Core or Enterprise)
- fathom – is Fathom Analytics present on the website?
- plausible – is the website tracked with Plausible Analytics?
- monsido_statistics – is the website tracked with Monsido Statistics?
- hotjar – does the website have Hotjar?
- Then, in the same way: adobe_analytics, new_relic, mixpanel, quantcast_measure, fullstory, cloudflare_insights, snowplow, klaviyo, ms_clarity, pingdom_rum and crazyegg.
The response is delivered as text/plain. Without a key, or with a key lacking the permission, the API answers 400 and 403 respectively.
4. Webhook for you with Webperf Premium
Webhooks are a way to have signals sent to your API when a SaaS service has something to tell you. As in this case, that one of Webperf's tests has run and has a test result for you. Read more about webhooks on Webperf.se
To benefit from webhooks via Webperf you first and foremost need to have a premium account. Set up an endpoint so you can receive the post from Webperf. Then you configure each website inside premium.webperf.se so we know where you want your result sent.
Below you have an example of what the content looks like that you get posted to your endpoint. The HTTP call will have a content-type of application/json and the payload below. You have two different signals about which page it concerns in the case of webhooks.
uri is the address you can later look up to check everything about the page as Webperf sees it. But if you test many pages continuously it's worth knowing that for webhooks there is also tested_url which directly tells you which page the test applies to. As usual, some tests don't evaluate that URL but instead go to your 404 page, check email settings, etc. But then you at least know which URL was fed in as the starting point.
{
"api_version": "undefined",
"uri": "https://api.webperf.se/item/3843",
"tested_url": "https://webperf.se",
"timestamp": "2024-01-13T22:34:11.519410",
"result_count": "1",
"data": {
"test_date": "2024-01-13T22:34:11.519410",
"type_of_test": 4,
"url": "https://webperf.se",
"rating": 4.95,
"check_report": "- Webbsidan kan ändå förbättras inom SEO.
- Tryckmålen har inte lämplig storlek: 99 % av tryckmålen har lämplig storlek ( 4.40 betyg )
- Alla bildelement har `[alt]`-attribut ( 5.00 betyg )
- Dokumentet har en metabeskrivning ( 5.00 betyg )
- Dokumentet har ett `<title>`-element ( 5.00 betyg )
- Dokumentet har ett giltigt `hreflang`-värde ( 5.00 betyg )
- Dokumentet har ett giltigt `rel=canonical`-värde ( 5.00 betyg )
- Dokumentet har läsliga teckenstorlekar ( 5.00 betyg )
- Dokumentet undviker plugin-program ( 5.00 betyg )
- Har en `<meta name="viewport">`-tagg med `width` eller `initial-scale` ( 5.00 betyg )
- Länkar har beskrivande text ( 5.00 betyg )
- Länkarna är genomsökningsbara ( 5.00 betyg )
- Sidan har en giltig HTTP-statuskod ( 5.00 betyg )
- Sidan är inte blockerad från indexering ( 5.00 betyg )
- robots.txt är giltig ( 5.00 betyg )",
"check_report_a11y": "",
"check_report_perf": "",
"check_report_stand": "",
"check_report_sec": "",
"json_check_data": "{}"
}
}
5. Version history
A brief look at the versions that have been released and what the plan is for the next version.
- 0.1 (2022-08-15) initial version with open data (municipalities and regions), plus three endpoints for premium; get your website's id number, fetch current test results in JSON format and historical average scores.
- 0.1.1 (2023-07-15) start a new run of your own website (Premium).
- 0.1.2 (2023-07-25) new features for premium and web agencies:
- Private tests of many pages on your website and get the results via API (Premium).
- Which websites use which web analytics tool? A list in CSV format of all public websites on Webperf.se and info about whether they use Google Analytics, Matomo, Plausible, Piwik PRO, Fathom, Siteimprove Analytics or Vizzit (requires the Premium for web agencies permission).
- 0.1.3 (2023-08-03) you can now also see whether the website uses Monsido Statistics (Premium for web agencies)
- 0.1.4 (2023-08-06) indicates whether the website uses Hotjar (Premium for web agencies)
- 0.1.5 (2023-08-25) if you have premium and post your API key to your own URI you get the calculated scores – the category scores (Premium).
- 0.1.6 (2023-09-08) BREAKING CHANGES!
- All HTTP headers that previously contained site_id or api_key must have their underscore changed to a hyphen. That is, site-id and api-key. This is due to the server-side framework which in newer versions can't handle underscores. (Premium)
- Calls for private tests now return which endpoints you'll find the tests at (Premium).
- More web analytics tools for you who want to know who uses what. Now there's also Adobe Analytics, New Relic, Mixpanel, Quantcast Measure, Fullstory, Cloudflare Insights, Snowplow, Klaviyo, Microsoft Clarity, Pingdom RUM and Crazyegg (requires the Premium for web agencies permission).
- 0.1.7 (2024-03-08) get readability index calculated for a text. (Premium)
- 0.1.8 (2024-03-25) BREAKING CHANGES!
- BREAKING: The endpoint https://api.webperf.se/stats/ and https://api.webperf.se/0.1/stats/ now gives a different response. See 2.1 Fetch your latest scores for how it works now
- A new feature is that if you have access to more than one website on Webperf's Premium you can reach all of them with the same API key. To see each website's endpoint, check the documentation under 2.1 Fetch your latest scores.
- 0.1.9 (2024-11-21) fetch the categories' average scores (Premium)
- 0.1.10 (2025-05-28) trigger an Audit (Premium)
- 1.0 (2025-08-04) refactored code, more stable operation and started supporting OpenAPI 3.
- 1.0.1 (2025-08-14) Supports OpenAPI 3 and Swagger UI so you can test the API without programming knowledge.
- 1.0.2 (2026-08-04) BREAKING CHANGES! for 2.11 Fetch your Premium Audits:
- BREAKING: The links in result_files no longer point at premium.webperf.se/static/results/ but at the new endpoint /audit_file/, which requires the same api-key and site-id as the listing. The report files are no longer publicly readable.
- BREAKING: site_id now holds the website's id. The row id used to sit there by mistake; it is now in result_id.
- New format audit_v2 with two more summaries plus summaries.zip. Rows with format csv have no result_files.
- 1.0.3 (2026-08-06) BREAKING CHANGES! for 2.10 Trigger a Premium Audit:
- BREAKING: content with a list of URLs of your own is no longer supported and returns status code 400. An audit has never been able to start from a submitted URL list – it always crawls its own way from the start page – and the list ended up in the same field as the page count, which meant the order ran with the auditor's default number of pages instead of the number you paid for.
- pages is required and decides both how many pages are crawled and what the order costs (1 credit per page). The API already required it; the documentation didn't mention it.
- The documentation showed GET for this endpoint; it has always been POST. The response is a JSON object, not a list, and the quota gate answers 400 with Quota exceeded instead of the old four-week rule's 429.
- BREAKING: a private one-off test costs 15 credits per page instead of 1, see 2.4 Start private tests. The API charged 1 credit while the web interface at webperf.cloud charged 15 for exactly the same order, out of the same credit account. The web interface's price is the one that stands.
- New section: 2.12 Remaining credits in your quota. The /quota/ endpoint has existed for a while but was missing from the documentation, so the only way to know what you had left was to log in or to have an order refused. Also corrected: credits run over a rolling 30-day period, not 4 weeks, and orders that do not fit really are refused.
- 1.0.4 (2026-09-04) new calls, two bugs fixed and a review of this documentation against what the API actually answers:
- New endpoint /0.1/whoami/ that tells you who the key belongs to and how many websites it reaches, see 2.1. The cheapest way to check a key.
- /0.1/stats/{id} takes the query parameters type_of_test and include_raw_data, so you no longer fetch raw data for every test when you want one. The listing /0.1/stats/ now also gives title and website per website.
- Fixed: /tools/lix/ answered 200 with an error message for texts under 50 words. Now 400.
- Fixed: /retest/ accepted an outdated list of test ids that lacked tests 26–32. Allowed ids now follow the active tests in /v1/tests. Test 17 (retired) is no longer accepted.
- Fixed: pagination.total in /v1/sites was miscounted.
- The documentation: 2.8 LIX is POST and has no /0.1/ alias; 2.5 takes no HTTP body; 2.2 has no data_id; 2.4 and 2.11 now show the actual response; 2.6 lists the four fields that actually arrive; 2.12 says 15 credits per private page; numbers in the older endpoints are described as the strings they are; and the open /v1/ endpoints are listed under 1.4.
- 1.0.5 (2026-10-11) BREAKING CHANGES! for timestamps and numbers in the older endpoints, plus three bugs fixed in the open endpoints, common field names, a complete OpenAPI specification and a review of section 1 against what the API actually answers:
- Fixed: meta.last_updated in /v1/public/municipalities and /v1/public/regions was always 2025-01-01. It is now the most recent day on which any website in the list got new ratings. meta.generated_at in /v1/public/stats is now the time of the call in UTC.
- /v1/public/stats now returns averages for all five ratings. standards and security were missing.
- Fixed: /info always reported public_sites as 1. It now reports the actual number. The list of endpoints is complete, and rate_limits describes the limits that actually apply instead of per-role limits that never existed.
- The OpenAPI specification now covers /v1/public/municipalities, /v1/public/regions, /v1/public/stats, /v1/sites, /v1/sites/{id} and /datasets/dcat, and the responses from /public-sector/ and /item/{id} have full schemas. The English specification had fallen behind and has been rebuilt.
- BREAKING: timestamps carry a time zone. timestamp in the older and the premium endpoints looks like 2026-10-11 21:09:21.423482+02:00, and test_date, date_added and date_modified carry the same offset. /health and the dates in /v1/sites/{id} are ISO 8601 with offset. Code that parses the time with a fixed format without a time zone needs adjusting.
- BREAKING: the older endpoints deliver numbers as numbers. result_count, id, site-ID, cat_id and type_of_test are integers, and the scores (rating, score, scores and the categories' rating_*) are decimals. A missing score is null instead of "-1", as in /v1/. Code that compares with "-1" or expects strings needs adjusting.
- Common field names. Every open endpoint has id, title, website and same_as. The older names name, url and sameAs remain with the same values, so nothing breaks.
- Municipalities and regions that are not open no longer appear in /public-sector/, /item/ without a key, /v1/sites and /v1/sites/{id}. That already applied to /v1/public/. With an API key that has access to the website, it is reached as before.
- In the documentation, 1.4 now describes the fields of each /v1/ endpoint, that limit is 10 unless given and when a rating is null. timestamp in 1.1 and 1.2 may come from a cache. url is usually but not always the start page. The section on rate limits describes the limits that actually apply.
6. Tips on tools and resources
To use Webperf's open data you can really just keep using your web browser. At least if you only want to download data. But for the premium API you need to send an API key in your request, which is most easily done with the Postman app if you're not building your call in some development environment.
- Postman to explore and work with APIs. Available for Mac, Linux and Windows, plus one you can run directly in the browser.
- Google Colab lets you run code directly in the browser via Google's cloud service. Supports Python code and the environment is a variant of Jupyter Notebook.
- Anaconda helps you with virtual environments with the various dependencies you may want, but is also a starting point for Jupyter Notebook to have an exploratory development environment directly in the browser. Available for Mac, Linux (including Raspberry Pi) and Windows.
- Visual Studio Code is a development environment for all sorts of languages. Available for Mac, Linux and Windows.
Resources:
- What every IT manager must know about APIs is a useful introduction to what APIs are good for (in Swedish)
- Sweden's data portal is a catalogue of data sources offered by DIGG.
- The official portal for European data lists 1.5 million datasets.
- Länkadedata.se offers a half-day course in DCAT-AP, semantic specifications, a white paper on linked open data, etc. (in Swedish)
- Sweden's data portal community is a good place for you who want to talk or collaborate about data sources.