{"id":13725157,"url":"https://github.com/treosh/crux-api","last_synced_at":"2025-06-13T11:36:30.006Z","repository":{"id":52250058,"uuid":"302435144","full_name":"treosh/crux-api","owner":"treosh","description":"A tiny (500 bytes) CrUX API wrapper that supports record \u0026 history API, handles errors, and provides types.","archived":false,"fork":false,"pushed_at":"2023-10-24T19:19:29.000Z","size":815,"stargazers_count":62,"open_issues_count":0,"forks_count":7,"subscribers_count":3,"default_branch":"main","last_synced_at":"2025-04-25T12:06:36.803Z","etag":null,"topics":["chrome-ux-report","core-web-vitals","web-performance"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/treosh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-10-08T18:56:35.000Z","updated_at":"2025-01-24T18:14:06.000Z","dependencies_parsed_at":"2022-08-30T19:50:41.885Z","dependency_job_id":"d53235d2-deda-48e4-b3b9-88598f5b89d4","html_url":"https://github.com/treosh/crux-api","commit_stats":{"total_commits":43,"total_committers":2,"mean_commits":21.5,"dds":"0.023255813953488413","last_synced_commit":"3bc91274d0dac6125e72b4ebaecc09389d264bd0"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treosh%2Fcrux-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treosh%2Fcrux-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treosh%2Fcrux-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/treosh%2Fcrux-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/treosh","download_url":"https://codeload.github.com/treosh/crux-api/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252272944,"owners_count":21721831,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["chrome-ux-report","core-web-vitals","web-performance"],"created_at":"2024-08-03T01:02:14.537Z","updated_at":"2025-05-04T00:31:29.389Z","avatar_url":"https://github.com/treosh.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# crux-api\n\n\u003e A tiny [CrUX API](https://developer.chrome.com/docs/crux/api/) wrapper that supports record \u0026 history API, handles errors, and provides types.\n\n**Motivation**: [CrUX API](https://developer.chrome.com/docs/crux/api/) is a fantastic tool to get RUM data without installing any script.\nWhile using the API in [Treo](https://treo.sh/), we discovered a few complex cases like API errors, rate limits, not found entries, URLs normalization, and TypeScript notations. We decided to build the `crux-api` library to make working with the CrUX API easier.\n\n**Features**:\n\n- A tiny (500 bytes) wrapper for [Chrome UX Report API](https://developers.google.com/web/tools/chrome-user-experience-report/api/reference);\n- Supports both the [record](https://developer.chrome.com/docs/crux/api/) \u0026 [history](https://developer.chrome.com/docs/crux/history-api/) API;\n- TypeScript notations for [options and responses](https://developer.chrome.com/docs/crux/api/#request-body);\n- Isomorphic: works in a browser and node.js;\n- Returns `null` for the `404 (CrUX data not found)` response;\n- Automatic retry when hits the API rate limits: `429 (Quota exceeded)`;\n- URL normalization helper to check the CrUX API index;\n\n## Usage\n\nInstall:\n\n```bash\nnpm install crux-api\n```\n\n**Fetch URL-level data for a various form factors and connections**:\n\n```js\nimport { createQueryRecord } from 'crux-api'\nconst queryRecord = createQueryRecord({ key: CRUX_API_KEY })\n\n// fetch all dimensions\nconst jsonRecord = await queryRecord({ url: 'https://github.com/marketplace?type=actions', formFactor: 'DESKTOP' })\n```\n\nThe `jsonRecord` is `null` or an `object` with [queryRecord response body](https://developer.chrome.com/docs/crux/api/#response-body), ex:\n\n```json\n{\n  \"record\": {\n    \"key\": {\n      \"formFactor\": \"DESKTOP\",\n      \"url\": \"https://github.com/marketplace\"\n    },\n    \"metrics\": {\n      \"first_contentful_paint\": {\n        \"histogram\": [\n          { \"start\": 0, \"end\": 1000, \"density\": 0.454180602006688 },\n          { \"start\": 1000, \"end\": 3000, \"density\": 0.52575250836120291 },\n          { \"start\": 3000, \"density\": 0.020066889632107024 }\n        ],\n        \"percentiles\": {\n          \"p75\": 1365\n        }\n      },\n      \"cumulative_layout_shift\": { ... },\n      \"first_input_delay\": { ... },\n      \"largest_contentful_paint\": { ... },\n      \"interaction_to_next_paint\": { ... },\n      \"experimental_time_to_first_byte\": { ... },\n    }\n  },\n  \"urlNormalizationDetails\": {\n    \"originalUrl\": \"https://github.com/marketplace?type=actions\",\n    \"normalizedUrl\": \"https://github.com/marketplace\"\n  }\n}\n```\n\n**Fetch historic data for a URL**:\n\n```js\nimport { createQueryRecord } from 'crux-api'\nconst queryRecord = createQueryHistoryRecord({ key: CRUX_API_KEY })\n\nconst jsonHistory = await queryRecord({ url: 'https://www.github.com/' }) // fetch ALL_FORM_FACTORS\n```\n\nThe `jsonHistory` is `null` or an `object` with [queryRecord response body](https://developer.chrome.com/docs/crux/history-api/#response-body), ex:\n\n```json\n{\n  \"record\": {\n    \"key\": {\n      \"url\": \"https://github.com/\"\n    },\n    \"metrics\": {\n      \"cumulative_layout_shift\": {\n        \"histogramTimeseries\": [\n          {\n            \"start\": \"0.00\",\n            \"end\": \"0.10\",\n            \"densities\": [0.716522216796875, 0.672149658203125, ...]\n          },\n          {\n            \"start\": \"0.10\",\n            \"end\": \"0.25\",\n            \"densities\": [0.244537353515625, 0.246917724609375, ...]\n          },\n          {\n            \"start\": \"0.25\",\n            \"densities\": [0.0389404296875, 0.0809326171875, ...]\n          }\n        ],\n        \"percentilesTimeseries\": {\n          \"p75s\": [\"0.10\", \"0.12\", ...]\n        }\n      },\n      \"experimental_time_to_first_byte\": { ... },\n      \"first_contentful_paint\": { ... },\n      \"first_input_delay\": { ... },\n      \"interaction_to_next_paint\": { ... },\n      \"largest_contentful_paint\": { ... }\n    }\n  }\n}\n```\n\n## API\n\n### createQueryRecord(createOptions)\n\nReturns a `queryRecord` function.\n\n- _createOptions.key_ (**required**) - CrUX API key, use https://goo.gle/crux-api-key to generate a new key;\n- _createOptions.fetch_ (optional, default: `window.fetch`) - pass a [WHATWG fetch](https://github.com/whatwg/fetch) implementation for a non-browser environment;\n\n#### queryRecord(queryOptions)\n\nFetches CrUX API using [`queryRecord options`](https://developer.chrome.com/docs/crux/api/):\n\n- _queryOptions.url_ or _queryOptions.origin_ (**required**) – the main identifier for a record lookup;\n- _queryOptions.formFactor_ (optional, defaults to all form factors) - the form factor dimension: `PHONE` | `DESKTOP` | `TABLET`;\n- _queryOptions.effectiveConnectionType_ (optional, defaults to all connections) - the effective network class: `4G` | `3G` | `2G` | `slow-2G` | `offline`.\n\nReturns a Promise with a raw [`queryRecord` response](https://developer.chrome.com/docs/crux/api/#response-body) or `null` when the data is not found.\n\n```js\nimport { createQueryRecord } from 'crux-api'\n\nconst queryRecord = createQueryRecord({ key: process.env.CRUX_API_KEY })\nconst res = await queryRecord({\n  url: 'https://github.com/marketplace?type=actions',\n  formFactor: 'DESKTOP',\n  effectiveConnectionType: '4G',\n})\n\n// res -\u003e URL-level data for https://github.com/marketplace\n```\n\n### createQueryHistoryRecord(historyOptions)\n\nReturns a function that fetches [CrUX History API using [`queryHistoryRecord options`](https://developer.chrome.com/docs/crux/history-api/#http-request):\n\n```js\nimport { createQueryHistoryRecord } from 'crux-api'\n\nconst queryHistory = createQueryHistoryRecord({ key: process.env.CRUX_API_KEY })\nconst res = await queryHistory({\n  url: 'https://www.github.com/',\n})\n```\n\n### normalizeUrl(url)\n\nNormalize a URL to match the CrUX API internal index.\nIt is a URL's `origin` + `pathname` ([source](./src/index.js#76)).\n\n```js\nimport { normalizeUrl } from 'crux-api'\n\nconsole.log(normalizeUrl('https://github.com/marketplace?type=actions')) // https://github.com/marketplace (removes search params)\nconsole.log(normalizeUrl('https://github.com')) // https://github.com/ (adds \"/\" to the end)\n```\n\n### CrUX API Responses\n\nThe `crux-api` is designed to return data and automatically handles errors. It returns an object for `200` responses, retries after `429`, and returns `null` for `404`.\nFor `400` and `5xx` it throws a relevant error.\n\nBelow are all known responses of [Chrome UX Report API](https://developers.google.com/web/tools/chrome-user-experience-report/api/reference) for easier debugging and development (The API documentation is vague about errors, [please, submit an issue](https://github.com/treosh/crux-api/issues), if you know other responses).\n\n\u003cdetails\u003e\n  \u003csummary\u003e✅ 200: URL-level CrUX History API data\u003c/summary\u003e\u003cbr\u003e\n\n```bash\ncurl -d url='https://github.com/' \\\n     -d formFactor=DESKTOP \\\n     'https://chromeuxreport.googleapis.com/v1/records:queryHistoryRecord?key=CRUX_API_KEY'\n```\n\n```json\n{\n  \"record\": {\n    \"key\": {\n      \"formFactor\": \"DESKTOP\",\n      \"url\": \"https://github.com/\"\n    },\n    \"metrics\": {\n      \"cumulative_layout_shift\": {\n        \"histogramTimeseries\": [\n          {\n            \"start\": \"0.00\",\n            \"end\": \"0.10\",\n            \"densities\": [\n              0.726043701171875, 0.676971435546875, 0.638519287109375, 0.629058837890625, 0.622161865234375,\n              0.656158447265625, 0.688262939453125, 0.73272705078125, 0.791351318359375, 0.845489501953125,\n              0.897674560546875, 0.916046142578125, 0.91455078125, 0.91363525390625, 0.913543701171875,\n              0.915008544921875, 0.9166259765625, 0.9210205078125, 0.929107666015625, 0.936553955078125,\n              0.93804931640625, 0.925628662109375, 0.913299560546875, 0.9024658203125, 0.903533935546875\n            ]\n          },\n          {\n            \"start\": \"0.10\",\n            \"end\": \"0.25\",\n            \"densities\": [\n              0.2373046875, 0.240753173828125, 0.224029541015625, 0.190032958984375, 0.1575927734375, 0.123931884765625,\n              0.10748291015625, 0.098846435546875, 0.087677001953125, 0.07757568359375, 0.069122314453125,\n              0.065460205078125, 0.064697265625, 0.06402587890625, 0.06298828125, 0.061614990234375, 0.0601806640625,\n              0.05560302734375, 0.048614501953125, 0.041778564453125, 0.041229248046875, 0.05340576171875,\n              0.0660400390625, 0.07568359375, 0.07342529296875\n            ]\n          },\n          {\n            \"start\": \"0.25\",\n            \"densities\": [\n              0.036651611328125, 0.082275390625, 0.137451171875, 0.180908203125, 0.220245361328125, 0.21990966796875,\n              0.204254150390625, 0.168426513671875, 0.1209716796875, 0.076934814453125, 0.033203125, 0.01849365234375,\n              0.020751953125, 0.0223388671875, 0.023468017578125, 0.02337646484375, 0.023193359375, 0.02337646484375,\n              0.02227783203125, 0.02166748046875, 0.020721435546875, 0.020965576171875, 0.020660400390625,\n              0.0218505859375, 0.023040771484375\n            ]\n          }\n        ],\n        \"percentilesTimeseries\": {\n          \"p75s\": [\n            \"0.10\",\n            \"0.11\",\n            \"0.12\",\n            \"0.14\",\n            \"0.18\",\n            \"0.17\",\n            \"0.14\",\n            \"0.10\",\n            \"0.08\",\n            \"0.07\",\n            \"0.06\",\n            \"0.06\",\n            \"0.06\",\n            \"0.06\",\n            \"0.06\",\n            \"0.06\",\n            \"0.06\",\n            \"0.06\",\n            \"0.05\",\n            \"0.05\",\n            \"0.04\",\n            \"0.05\",\n            \"0.05\",\n            \"0.05\",\n            \"0.05\"\n          ]\n        }\n      },\n      \"experimental_time_to_first_byte\": {\n        \"histogramTimeseries\": [\n          {\n            \"start\": 0,\n            \"end\": 800,\n            \"densities\": [\n              0.779144287109375, 0.780303955078125, 0.777435302734375, 0.77899169921875, 0.780487060546875,\n              0.779144287109375, 0.77862548828125, 0.776763916015625, 0.774810791015625, 0.76995849609375,\n              0.765777587890625, 0.75335693359375, 0.741180419921875, 0.73614501953125, 0.732025146484375,\n              0.7298583984375, 0.7265625, 0.72662353515625, 0.724853515625, 0.72650146484375, 0.7236328125,\n              0.718994140625, 0.717437744140625, 0.71881103515625, 0.721832275390625\n            ]\n          },\n          {\n            \"start\": 800,\n            \"end\": 1800,\n            \"densities\": [\n              0.1845703125, 0.184783935546875, 0.187591552734375, 0.186492919921875, 0.186920166015625,\n              0.189056396484375, 0.190155029296875, 0.193328857421875, 0.1947021484375, 0.19903564453125,\n              0.202911376953125, 0.21380615234375, 0.22515869140625, 0.22967529296875, 0.232208251953125,\n              0.23468017578125, 0.23553466796875, 0.236907958984375, 0.237640380859375, 0.2371826171875,\n              0.23992919921875, 0.24432373046875, 0.245819091796875, 0.24505615234375, 0.242095947265625\n            ]\n          },\n          {\n            \"start\": 1800,\n            \"densities\": [\n              0.036285400390625, 0.034912109375, 0.03497314453125, 0.034515380859375, 0.0325927734375, 0.03179931640625,\n              0.031219482421875, 0.0299072265625, 0.030487060546875, 0.031005859375, 0.03131103515625, 0.0328369140625,\n              0.033660888671875, 0.0341796875, 0.0357666015625, 0.03546142578125, 0.03790283203125, 0.036468505859375,\n              0.037506103515625, 0.03631591796875, 0.03643798828125, 0.03668212890625, 0.0367431640625, 0.0361328125,\n              0.03607177734375\n            ]\n          }\n        ],\n        \"percentilesTimeseries\": {\n          \"p75s\": [\n            748, 749, 752, 752, 751, 752, 755, 757, 761, 768, 778, 796, 814, 821, 826, 832, 832, 834, 836, 836, 838,\n            846, 847, 846, 841\n          ]\n        }\n      },\n      \"first_contentful_paint\": {\n        \"histogramTimeseries\": [\n          {\n            \"start\": 0,\n            \"end\": 1800,\n            \"densities\": [\n              0.88543701171875, 0.88568115234375, 0.886962890625, 0.889556884765625, 0.8934326171875, 0.89837646484375,\n              0.90142822265625, 0.903594970703125, 0.900787353515625, 0.899627685546875, 0.894317626953125,\n              0.8936767578125, 0.89227294921875, 0.89227294921875, 0.8905029296875, 0.891815185546875, 0.88812255859375,\n              0.88897705078125, 0.888946533203125, 0.888458251953125, 0.889923095703125, 0.88800048828125,\n              0.88433837890625, 0.88311767578125, 0.880706787109375\n            ]\n          },\n          {\n            \"start\": 1800,\n            \"end\": 3000,\n            \"densities\": [\n              0.07373046875, 0.07440185546875, 0.072662353515625, 0.0693359375, 0.0662841796875, 0.063446044921875,\n              0.061248779296875, 0.06024169921875, 0.061920166015625, 0.06378173828125, 0.06536865234375,\n              0.066314697265625, 0.0675048828125, 0.066741943359375, 0.06787109375, 0.0675048828125, 0.0699462890625,\n              0.06915283203125, 0.068267822265625, 0.06878662109375, 0.068267822265625, 0.070343017578125,\n              0.072509765625, 0.072418212890625, 0.073883056640625\n            ]\n          },\n          {\n            \"start\": 3000,\n            \"densities\": [\n              0.04083251953125, 0.0399169921875, 0.040374755859375, 0.041107177734375, 0.040283203125,\n              0.038177490234375, 0.037322998046875, 0.036163330078125, 0.03729248046875, 0.036590576171875,\n              0.040313720703125, 0.040008544921875, 0.04022216796875, 0.040985107421875, 0.0416259765625,\n              0.040679931640625, 0.04193115234375, 0.0418701171875, 0.04278564453125, 0.042755126953125,\n              0.04180908203125, 0.041656494140625, 0.04315185546875, 0.044464111328125, 0.04541015625\n            ]\n          }\n        ],\n        \"percentilesTimeseries\": {\n          \"p75s\": [\n            1221, 1216, 1219, 1205, 1186, 1173, 1158, 1157, 1165, 1175, 1190, 1204, 1214, 1217, 1222, 1227, 1231, 1237,\n            1237, 1237, 1236, 1250, 1263, 1272, 1276\n          ]\n        }\n      },\n      \"first_input_delay\": {\n        \"histogramTimeseries\": [\n          {\n            \"start\": 0,\n            \"end\": 100,\n            \"densities\": [\n              0.970855712890625, 0.971649169921875, 0.97064208984375, 0.969085693359375, 0.96905517578125,\n              0.968017578125, 0.969146728515625, 0.96868896484375, 0.9720458984375, 0.971710205078125, 0.9720458984375,\n              0.97308349609375, 0.974609375, 0.9749755859375, 0.974090576171875, 0.97412109375, 0.9752197265625,\n              0.97528076171875, 0.9747314453125, 0.973236083984375, 0.973846435546875, 0.97296142578125,\n              0.974884033203125, 0.97357177734375, 0.975128173828125\n            ]\n          },\n          {\n            \"start\": 100,\n            \"end\": 300,\n            \"densities\": [\n              0.01763916015625, 0.01641845703125, 0.017730712890625, 0.0181884765625, 0.018218994140625,\n              0.019622802734375, 0.01849365234375, 0.019256591796875, 0.0172119140625, 0.017608642578125,\n              0.017059326171875, 0.016876220703125, 0.015350341796875, 0.014984130859375, 0.0159912109375,\n              0.016021728515625, 0.014495849609375, 0.0145263671875, 0.014739990234375, 0.0159912109375,\n              0.01568603515625, 0.016204833984375, 0.014739990234375, 0.01617431640625, 0.01416015625\n            ]\n          },\n          {\n            \"start\": 300,\n            \"densities\": [\n              0.011505126953125, 0.011932373046875, 0.011627197265625, 0.012725830078125, 0.012725830078125,\n              0.012359619140625, 0.012359619140625, 0.012054443359375, 0.0107421875, 0.01068115234375,\n              0.010894775390625, 0.010040283203125, 0.010040283203125, 0.010040283203125, 0.009918212890625,\n              0.009857177734375, 0.010284423828125, 0.01019287109375, 0.010528564453125, 0.010772705078125,\n              0.010467529296875, 0.010833740234375, 0.0103759765625, 0.01025390625, 0.010711669921875\n            ]\n          }\n        ],\n        \"percentilesTimeseries\": {\n          \"p75s\": [3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3]\n        }\n      },\n      \"interaction_to_next_paint\": {\n        \"histogramTimeseries\": [\n          {\n            \"start\": 0,\n            \"end\": 200,\n            \"densities\": [\n              0.9437255859375, 0.944244384765625, 0.94207763671875, 0.938720703125, 0.936737060546875,\n              0.936126708984375, 0.93768310546875, 0.93988037109375, 0.94134521484375, 0.9393310546875, 0.9384765625,\n              0.939208984375, 0.937744140625, 0.9365234375, 0.937286376953125, 0.937896728515625, 0.937591552734375,\n              0.93682861328125, 0.9373779296875, 0.93505859375, 0.9368896484375, 0.9373779296875, 0.937255859375,\n              0.938629150390625, 0.940155029296875\n            ]\n          },\n          {\n            \"start\": 200,\n            \"end\": 500,\n            \"densities\": [\n              0.03204345703125, 0.032135009765625, 0.034271240234375, 0.0360107421875, 0.0382080078125, 0.0384521484375,\n              0.038360595703125, 0.037994384765625, 0.036376953125, 0.037841796875, 0.038848876953125, 0.03875732421875,\n              0.039947509765625, 0.04107666015625, 0.040435791015625, 0.039337158203125, 0.039947509765625,\n              0.040313720703125, 0.04034423828125, 0.04168701171875, 0.0406494140625, 0.03924560546875,\n              0.039581298828125, 0.039459228515625, 0.03814697265625\n            ]\n          },\n          {\n            \"start\": 500,\n            \"densities\": [\n              0.02423095703125, 0.02362060546875, 0.023651123046875, 0.0252685546875, 0.025054931640625,\n              0.025421142578125, 0.023956298828125, 0.022125244140625, 0.02227783203125, 0.0228271484375,\n              0.022674560546875, 0.02203369140625, 0.022308349609375, 0.02239990234375, 0.02227783203125,\n              0.02276611328125, 0.0224609375, 0.022857666015625, 0.02227783203125, 0.02325439453125, 0.0224609375,\n              0.02337646484375, 0.023162841796875, 0.02191162109375, 0.021697998046875\n            ]\n          }\n        ],\n        \"percentilesTimeseries\": {\n          \"p75s\": [61, 62, 63, 64, 65, 66, 66, 66, 66, 67, 68, 70, 72, 73, 73, 72, 72, 73, 72, 71, 70, 70, 69, 69, 69]\n        }\n      },\n      \"largest_contentful_paint\": {\n        \"histogramTimeseries\": [\n          {\n            \"start\": 0,\n            \"end\": 2500,\n            \"densities\": [\n              0.86895751953125, 0.850921630859375, 0.834320068359375, 0.818145751953125, 0.802490234375,\n              0.796417236328125, 0.79620361328125, 0.809417724609375, 0.830078125, 0.850067138671875, 0.87017822265625,\n              0.87786865234375, 0.87628173828125, 0.875823974609375, 0.875335693359375, 0.867889404296875,\n              0.869781494140625, 0.87115478515625, 0.869476318359375, 0.874481201171875, 0.877227783203125,\n              0.884185791015625, 0.890472412109375, 0.895751953125, 0.896820068359375\n            ]\n          },\n          {\n            \"start\": 2500,\n            \"end\": 4000,\n            \"densities\": [\n              0.08221435546875, 0.09649658203125, 0.10797119140625, 0.11907958984375, 0.130035400390625,\n              0.1356201171875, 0.135101318359375, 0.12530517578125, 0.110565185546875, 0.095550537109375,\n              0.07904052734375, 0.072845458984375, 0.074127197265625, 0.0743408203125, 0.07452392578125,\n              0.080596923828125, 0.07769775390625, 0.078460693359375, 0.0782470703125, 0.074798583984375,\n              0.07415771484375, 0.0692138671875, 0.06475830078125, 0.0615234375, 0.0595703125\n            ]\n          },\n          {\n            \"start\": 4000,\n            \"densities\": [\n              0.048828125, 0.052581787109375, 0.057708740234375, 0.062774658203125, 0.067474365234375,\n              0.067962646484375, 0.068695068359375, 0.065277099609375, 0.059356689453125, 0.05438232421875, 0.05078125,\n              0.049285888671875, 0.049591064453125, 0.049835205078125, 0.050140380859375, 0.051513671875,\n              0.052520751953125, 0.050384521484375, 0.052276611328125, 0.05072021484375, 0.048614501953125,\n              0.046600341796875, 0.044769287109375, 0.042724609375, 0.043609619140625\n            ]\n          }\n        ],\n        \"percentilesTimeseries\": {\n          \"p75s\": [\n            1815, 1953, 2056, 2148, 2236, 2271, 2273, 2200, 2068, 1918, 1757, 1695, 1715, 1719, 1726, 1772, 1760, 1760,\n            1762, 1726, 1701, 1657, 1618, 1579, 1556\n          ]\n        }\n      }\n    },\n    \"collectionPeriods\": [\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 3,\n          \"day\": 26\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 4,\n          \"day\": 22\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 4,\n          \"day\": 2\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 4,\n          \"day\": 29\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 4,\n          \"day\": 9\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 5,\n          \"day\": 6\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 4,\n          \"day\": 16\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 5,\n          \"day\": 13\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 4,\n          \"day\": 23\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 5,\n          \"day\": 20\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 4,\n          \"day\": 30\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 5,\n          \"day\": 27\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 5,\n          \"day\": 7\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 6,\n          \"day\": 3\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 5,\n          \"day\": 14\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 6,\n          \"day\": 10\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 5,\n          \"day\": 21\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 6,\n          \"day\": 17\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 5,\n          \"day\": 28\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 6,\n          \"day\": 24\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 6,\n          \"day\": 4\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 7,\n          \"day\": 1\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 6,\n          \"day\": 11\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 7,\n          \"day\": 8\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 6,\n          \"day\": 18\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 7,\n          \"day\": 15\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 6,\n          \"day\": 25\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 7,\n          \"day\": 22\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 7,\n          \"day\": 2\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 7,\n          \"day\": 29\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 7,\n          \"day\": 9\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 8,\n          \"day\": 5\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 7,\n          \"day\": 16\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 8,\n          \"day\": 12\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 7,\n          \"day\": 23\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 8,\n          \"day\": 19\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 7,\n          \"day\": 30\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 8,\n          \"day\": 26\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 8,\n          \"day\": 6\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 9,\n          \"day\": 2\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 8,\n          \"day\": 13\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 9,\n          \"day\": 9\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 8,\n          \"day\": 20\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 9,\n          \"day\": 16\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 8,\n          \"day\": 27\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 9,\n          \"day\": 23\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 9,\n          \"day\": 3\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 9,\n          \"day\": 30\n        }\n      },\n      {\n        \"firstDate\": {\n          \"year\": 2023,\n          \"month\": 9,\n          \"day\": 10\n        },\n        \"lastDate\": {\n          \"year\": 2023,\n          \"month\": 10,\n          \"day\": 7\n        }\n      }\n    ]\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e✅ 200: URL-level CrUX API data\u003c/summary\u003e\u003cbr\u003e\n\n```bash\ncurl -d url='https://github.com/marketplace?type=actions' \\\n     -d effectiveConnectionType=4G \\\n     -d formFactor=DESKTOP \\\n     'https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=CRUX_API_KEY'\n```\n\n```json\n{\n  \"record\": {\n    \"key\": {\n      \"formFactor\": \"DESKTOP\",\n      \"effectiveConnectionType\": \"4G\",\n      \"url\": \"https://github.com/marketplace\"\n    },\n    \"metrics\": {\n      \"cumulative_layout_shift\": {\n        \"histogram\": [\n          {\n            \"start\": \"0.00\",\n            \"end\": \"0.10\",\n            \"density\": 0.9430604982206409\n          },\n          {\n            \"start\": \"0.10\",\n            \"end\": \"0.25\",\n            \"density\": 0.020804817957842878\n          },\n          {\n            \"start\": \"0.25\",\n            \"density\": 0.03613468382151657\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": \"0.02\"\n        }\n      },\n      \"experimental_time_to_first_byte\": {\n        \"histogram\": [\n          {\n            \"start\": 0,\n            \"end\": 800,\n            \"density\": 0.9393059587999442\n          },\n          {\n            \"start\": 800,\n            \"end\": 1800,\n            \"density\": 0.05378128024332917\n          },\n          {\n            \"start\": 1800,\n            \"density\": 0.006912760956726073\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": 550\n        }\n      },\n      \"first_contentful_paint\": {\n        \"histogram\": [\n          {\n            \"start\": 0,\n            \"end\": 1800,\n            \"density\": 0.9731800766283532\n          },\n          {\n            \"start\": 1800,\n            \"end\": 3000,\n            \"density\": 0.017651888341543534\n          },\n          {\n            \"start\": 3000,\n            \"density\": 0.009168035030104028\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": 809\n        }\n      },\n      \"first_input_delay\": {\n        \"histogram\": [\n          {\n            \"start\": 0,\n            \"end\": 100,\n            \"density\": 0.9936164307521526\n          },\n          {\n            \"start\": 100,\n            \"end\": 300,\n            \"density\": 0.004579517069109083\n          },\n          {\n            \"start\": 300,\n            \"density\": 0.0018040521787399426\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": 3\n        }\n      },\n      \"interaction_to_next_paint\": {\n        \"histogram\": [\n          {\n            \"start\": 0,\n            \"end\": 200,\n            \"density\": 0.9759848893685868\n          },\n          {\n            \"start\": 200,\n            \"end\": 500,\n            \"density\": 0.014301133297355571\n          },\n          {\n            \"start\": 500,\n            \"density\": 0.009713977334052826\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": 50\n        }\n      },\n      \"largest_contentful_paint\": {\n        \"histogram\": [\n          {\n            \"start\": 0,\n            \"end\": 2500,\n            \"density\": 0.9798854493386074\n          },\n          {\n            \"start\": 2500,\n            \"end\": 4000,\n            \"density\": 0.012886949406791222\n          },\n          {\n            \"start\": 4000,\n            \"density\": 0.007227601254602516\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": 895\n        }\n      }\n    },\n    \"collectionPeriod\": {\n      \"firstDate\": {\n        \"year\": 2023,\n        \"month\": 9,\n        \"day\": 15\n      },\n      \"lastDate\": {\n        \"year\": 2023,\n        \"month\": 10,\n        \"day\": 12\n      }\n    }\n  },\n  \"urlNormalizationDetails\": {\n    \"originalUrl\": \"https://github.com/marketplace?type=actions\",\n    \"normalizedUrl\": \"https://github.com/marketplace\"\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e✅ 200: Origin-level CrUX API data\u003c/summary\u003e\u003cbr\u003e\n\n```bash\ncurl -d origin='https://github.com' \\\n     -d formFactor=PHONE \\\n     'https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=CRUX_API_KEY'\n```\n\n```json\n{\n  \"record\": {\n    \"key\": {\n      \"formFactor\": \"PHONE\",\n      \"origin\": \"https://github.com\"\n    },\n    \"metrics\": {\n      \"first_input_delay\": {\n        \"histogram\": [\n          {\n            \"start\": 0,\n            \"end\": 100,\n            \"density\": 0.9498680738786286\n          },\n          {\n            \"start\": 100,\n            \"end\": 300,\n            \"density\": 0.03430079155672826\n          },\n          {\n            \"start\": 300,\n            \"density\": 0.015831134564643756\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": 17\n        }\n      },\n      \"interaction_to_next_paint\": {\n        \"histogram\": [\n          {\n            \"start\": 0,\n            \"end\": 200,\n            \"density\": 0.6478405315614636\n          },\n          {\n            \"start\": 200,\n            \"end\": 500,\n            \"density\": 0.24584717607973486\n          },\n          {\n            \"start\": 500,\n            \"density\": 0.10631229235880371\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": 272\n        }\n      },\n      \"largest_contentful_paint\": {\n        \"histogram\": [\n          {\n            \"start\": 0,\n            \"end\": 2500,\n            \"density\": 0.7900432900432863\n          },\n          {\n            \"start\": 2500,\n            \"end\": 4000,\n            \"density\": 0.13528138528138467\n          },\n          {\n            \"start\": 4000,\n            \"density\": 0.0746753246753239\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": 2312\n        }\n      },\n      \"cumulative_layout_shift\": {\n        \"histogram\": [\n          {\n            \"start\": \"0.00\",\n            \"end\": \"0.10\",\n            \"density\": 0.8527302813017104\n          },\n          {\n            \"start\": \"0.10\",\n            \"end\": \"0.25\",\n            \"density\": 0.09817981246552682\n          },\n          {\n            \"start\": \"0.25\",\n            \"density\": 0.04908990623276335\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": \"0.02\"\n        }\n      },\n      \"experimental_time_to_first_byte\": {\n        \"histogram\": [\n          {\n            \"start\": 0,\n            \"end\": 800,\n            \"density\": 0.6018518518518505\n          },\n          {\n            \"start\": 800,\n            \"end\": 1800,\n            \"density\": 0.3312757201646084\n          },\n          {\n            \"start\": 1800,\n            \"density\": 0.0668724279835391\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": 1039\n        }\n      },\n      \"first_contentful_paint\": {\n        \"histogram\": [\n          {\n            \"start\": 0,\n            \"end\": 1800,\n            \"density\": 0.7165570175438571\n          },\n          {\n            \"start\": 1800,\n            \"end\": 3000,\n            \"density\": 0.1781798245614029\n          },\n          {\n            \"start\": 3000,\n            \"density\": 0.10526315789473623\n          }\n        ],\n        \"percentiles\": {\n          \"p75\": 1934\n        }\n      }\n    },\n    \"collectionPeriod\": {\n      \"firstDate\": {\n        \"year\": 2023,\n        \"month\": 9,\n        \"day\": 15\n      },\n      \"lastDate\": {\n        \"year\": 2023,\n        \"month\": 10,\n        \"day\": 12\n      }\n    }\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e🛑 400 INVALID_ARGUMENT: API key not valid, please pass a valid API key\u003c/summary\u003e\u003cbr\u003e\n\n```bash\ncurl -d origin='https://github.com' \\\n     'https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=INVALID_KEY'\n```\n\n```json\n{\n  \"error\": {\n    \"code\": 400,\n    \"message\": \"API key not valid. Please pass a valid API key.\",\n    \"status\": \"INVALID_ARGUMENT\",\n    \"details\": [\n      {\n        \"@type\": \"type.googleapis.com/google.rpc.Help\",\n        \"links\": [\n          {\n            \"description\": \"Google developers console\",\n            \"url\": \"https://console.developers.google.com\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e🛑 400 INVALID_ARGUMENT: Invalid value at 'form_factor'/'ect'\u003c/summary\u003e\u003cbr\u003e\n\n```bash\ncurl -d url='https://github.com/' \\\n     -d formFactor=mobile  \\\n     'https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=CRUX_API_KEY'\n```\n\n```json\n{\n  \"error\": {\n    \"code\": 400,\n    \"message\": \"Invalid value at 'form_factor' (type.googleapis.com/google.chrome.uxreport.v1.FormFactor), \\\"mobile\\\"\",\n    \"status\": \"INVALID_ARGUMENT\",\n    \"details\": [\n      {\n        \"@type\": \"type.googleapis.com/google.rpc.BadRequest\",\n        \"fieldViolations\": [\n          {\n            \"field\": \"form_factor\",\n            \"description\": \"Invalid value at 'form_factor' (type.googleapis.com/google.chrome.uxreport.v1.FormFactor), \\\"mobile\\\"\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e🛑 404 NOT_FOUND: chrome ux report data not found\u003c/summary\u003e\u003cbr\u003e\n\n```bash\ncurl -d url='https://github.com/search' \\\n     'https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=CRUX_API_KEY'\n```\n\n```json\n{\n  \"error\": {\n    \"code\": 404,\n    \"message\": \"chrome ux report data not found\",\n    \"status\": \"NOT_FOUND\"\n  }\n}\n```\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e🛑 429 RESOURCE_EXHAUSTED: Quota exceeded limit 'Queries per 100 seconds' of service\u003c/summary\u003e\u003cbr\u003e\n\n```bash\ncurl -d url='https://github.com/search' \\\n     'https://chromeuxreport.googleapis.com/v1/records:queryRecord?key=CRUX_API_KEY'\n```\n\n```json\n{\n  \"code\": 429,\n  \"message\": \"Quota exceeded for quota group 'default' and limit 'Queries per 100 seconds' of service 'chromeuxreport.googleapis.com' for consumer 'project_number:00000000000000'.\",\n  \"status\": \"RESOURCE_EXHAUSTED\",\n  \"details\": [\n    {\n      \"@type\": \"type.googleapis.com/google.rpc.Help\",\n      \"links\": [\n        {\n          \"description\": \"Google developer console API key\",\n          \"url\": \"https://console.developers.google.com/project/00000000000000/apiui/credential\"\n        }\n      ]\n    }\n  ]\n}\n```\n\n\u003c/details\u003e\n\n## Credits\n\nSponsored by [Treo - Page speed monitoring made simple](https://treo.sh/).\n\n[![](https://github.com/treosh/crux-api/workflows/CI/badge.svg)](https://github.com/treosh/crux-api/actions?workflow=CI)\n[![](https://img.shields.io/npm/v/crux-api.svg)](https://npmjs.org/package/crux-api)\n[![](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftreosh%2Fcrux-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftreosh%2Fcrux-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftreosh%2Fcrux-api/lists"}