{"id":13426461,"url":"https://github.com/matthewmueller/x-ray","last_synced_at":"2026-10-18T23:45:02.472Z","repository":{"id":26868935,"uuid":"30329296","full_name":"matthewmueller/x-ray","owner":"matthewmueller","description":"The next web scraper. See through the \u003chtml\u003e noise.","archived":false,"fork":false,"pushed_at":"2026-08-31T19:56:44.000Z","size":1343,"stargazers_count":5904,"open_issues_count":74,"forks_count":342,"subscribers_count":103,"default_branch":"master","last_synced_at":"2026-10-12T07:27:27.460Z","etag":null,"topics":[],"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/matthewmueller.png","metadata":{"files":{"readme":"Readme.md","changelog":"CHANGELOG.md","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"claude":null,"gemini":null,"cursor":null,"copilot":null,"dco":null,"cla":null,"disclosure":null}},"created_at":"2015-02-05T00:34:16.000Z","updated_at":"2026-10-12T07:16:52.000Z","dependencies_parsed_at":"2026-10-04T05:29:43.942Z","dependency_job_id":null,"html_url":"https://github.com/matthewmueller/x-ray","commit_stats":{"total_commits":195,"total_committers":44,"mean_commits":4.431818181818182,"dds":0.717948717948718,"last_synced_commit":"3f9ad8766e5288c53d8efecadc239b0d490761f8"},"previous_names":["lapwinglabs/x-ray"],"tags_count":18,"template":false,"template_full_name":null,"purl":"pkg:github/matthewmueller/x-ray","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewmueller%2Fx-ray","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewmueller%2Fx-ray/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewmueller%2Fx-ray/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewmueller%2Fx-ray/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matthewmueller","download_url":"https://codeload.github.com/matthewmueller/x-ray/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matthewmueller%2Fx-ray/sbom","scorecard":{"id":91386,"data":{"date":"2022-08-15","repo":{"name":"github.com/matthewmueller/x-ray","commit":"3f9ad8766e5288c53d8efecadc239b0d490761f8"},"scorecard":{"version":"v4.5.0-26-g10b6052","commit":"10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93"},"score":6.2,"checks":[{"name":"Maintained","score":0,"reason":"0 commit(s) out of 30 and 0 issue activity out of 30 found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#maintained"}},{"name":"Code-Review","score":5,"reason":"GitHub code reviews found for 17 commits out of the last 30 -- score normalized to 5","details":["Warn: no reviews found for commit: 40db2e615c9bc37db10b26d123f15cc4ca15c01c","Warn: no reviews found for commit: 8c5dbcd99c45db947ee8756d68dc2f1def52eafc","Warn: no reviews found for commit: 5d053412c95101f891379abfae6443877d551df8","Warn: no reviews found for commit: 6167fc0e38020a9528e6180a58fa16c5c90795a8","Warn: no reviews found for commit: 7ed40fa86bc3444bd888daad833e6c567d9218d8","Warn: no reviews found for commit: 0741ec165b2e3ba67d9940b0d8b764f84180b94b","Warn: no reviews found for commit: e08f15496e7f9db73458be1dca7e8c90a313b428","Warn: no reviews found for commit: 6db07551ba45fb84a933ce224b8934d75faddeab","Warn: no reviews found for commit: c0afaefe2757a51a1b72315ac59c360bb3b19be9","Warn: no reviews found for commit: c060cdc9a96ab20f3df59ed618f704d27c359362","Warn: no reviews found for commit: bcc2aedc7cddf91baea543cad0205979d76fcd4a","Warn: no reviews found for commit: 02a09722536f6322ddc2ec89c23e13867cc5fd17","Warn: no reviews found for commit: b6fc1039b1f72ef3c1f67db3b24cf351a36ff2fe"],"documentation":{"short":"Determines if the project requires code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#code-review"}},{"name":"CII-Best-Practices","score":0,"reason":"no badge detected","details":null,"documentation":{"short":"Determines if the project has a CII Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#cii-best-practices"}},{"name":"Vulnerabilities","score":10,"reason":"no vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":["Warn: no GitHub releases found"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#branch-protection"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#dangerous-workflow"}},{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: Renovabot detected: renovate.json:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#dependency-update-tool"}},{"name":"Packaging","score":-1,"reason":"no published package detected","details":["Warn: no GitHub publishing workflow detected"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":10,"reason":"tokens are read-only in GitHub workflows","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#token-permissions"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: : LICENSE:1"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#license"}},{"name":"Pinned-Dependencies","score":10,"reason":"all dependencies are pinned","details":["Info: GitHub-owned GitHubActions are pinned","Info: Third-party GitHubActions are pinned","Info: Dockerfile dependencies are pinned","Info: no insecure (not pinned by hash) dependency downloads found in Dockerfiles","Info: no insecure (not pinned by hash) dependency downloads found in shell scripts"],"documentation":{"short":"Determines if the project has declared and pinned its dependencies.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#binary-artifacts"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":null,"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":null,"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/10b6052acfb4f0b8136bc4876cb6f5b6f26bfe93/docs/checks.md#fuzzing"}}]},"last_synced_at":"2025-08-15T07:59:07.270Z","repository_id":26868935,"created_at":"2025-08-15T07:59:07.270Z","updated_at":"2025-08-15T07:59:07.270Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":344872684,"owners_count":38343425,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-10-03T21:59:58.778Z","status":"online","status_checked_at":"2026-10-18T02:00:06.448Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":[],"created_at":"2024-07-31T00:01:35.165Z","updated_at":"2026-10-18T23:45:02.200Z","avatar_url":"https://github.com/matthewmueller.png","language":"JavaScript","funding_links":["https://opencollective.com/x-ray","https://opencollective.com/x-ray/backer/0/website","https://opencollective.com/x-ray/backer/1/website","https://opencollective.com/x-ray/backer/2/website","https://opencollective.com/x-ray/backer/3/website","https://opencollective.com/x-ray/backer/4/website","https://opencollective.com/x-ray/backer/5/website","https://opencollective.com/x-ray/backer/6/website","https://opencollective.com/x-ray/backer/7/website","https://opencollective.com/x-ray/backer/8/website","https://opencollective.com/x-ray/backer/9/website","https://opencollective.com/x-ray/backer/10/website","https://opencollective.com/x-ray/backer/11/website","https://opencollective.com/x-ray/backer/12/website","https://opencollective.com/x-ray/backer/13/website","https://opencollective.com/x-ray/backer/14/website","https://opencollective.com/x-ray/backer/15/website","https://opencollective.com/x-ray/backer/16/website","https://opencollective.com/x-ray/backer/17/website","https://opencollective.com/x-ray/backer/18/website","https://opencollective.com/x-ray/backer/19/website","https://opencollective.com/x-ray/backer/20/website","https://opencollective.com/x-ray/backer/21/website","https://opencollective.com/x-ray/backer/22/website","https://opencollective.com/x-ray/backer/23/website","https://opencollective.com/x-ray/backer/24/website","https://opencollective.com/x-ray/backer/25/website","https://opencollective.com/x-ray/backer/26/website","https://opencollective.com/x-ray/backer/27/website","https://opencollective.com/x-ray/backer/28/website","https://opencollective.com/x-ray/backer/29/website"],"categories":["Packages","JavaScript","others","Tools","Web Development","Nodejs","包"],"sub_categories":["Parsing","Related tools","解析"],"readme":"![x-ray](https://cldup.com/fMBbTcVtwB.png)\n\n![Last version](https://img.shields.io/github/tag/matthewmueller/x-ray.svg?style=flat-square)\n[![Build Status](http://img.shields.io/travis/matthewmueller/x-ray/master.svg?style=flat-square)](https://travis-ci.org/matthewmueller/x-ray)\n[![Coverage Status](https://coveralls.io/repos/github/matthewmueller/x-ray/badge.svg?branch=master\u0026style=flat-square)](https://coveralls.io/github/matthewmueller/x-ray?branch=master)\n[![Dependency status](http://img.shields.io/david/matthewmueller/x-ray.svg?style=flat-square)](https://david-dm.org/matthewmueller/x-ray)\n[![Dev Dependencies Status](http://img.shields.io/david/dev/matthewmueller/x-ray.svg?style=flat-square)](https://david-dm.org/matthewmueller/x-ray#info=devDependencies)\n[![NPM Status](http://img.shields.io/npm/dm/x-ray.svg?style=flat-square)](https://www.npmjs.org/package/x-ray)\n![Node version](https://img.shields.io/node/v/x-ray.svg?style=flat-square)\n[![OpenCollective](https://opencollective.com/x-ray/backers/badge.svg)](#backers)\n[![OpenCollective](https://opencollective.com/x-ray/sponsors/badge.svg)](#sponsors)\n[![Gitter](https://badges.gitter.im/lapwinglabs/x-ray.svg)](https://gitter.im/lapwinglabs/x-ray?utm_source=badge\u0026utm_medium=badge\u0026utm_campaign=pr-badge)\n\n```js\nvar Xray = require('x-ray')\nvar x = Xray()\n\nx('https://blog.ycombinator.com/', '.post', [\n  {\n    title: 'h1 a',\n    link: '.article-title@href'\n  }\n])\n  .paginate('.nav-previous a@href')\n  .limit(3)\n  .write('results.json')\n```\n\n## Installation\n\n```\nnpm install x-ray\n```\n\n## Features\n\n- **Flexible schema:** Supports strings, arrays, arrays of objects, and nested object structures. The schema is not tied to the structure of the page you're scraping, allowing you to pull the data in the structure of your choosing.\n\n- **Composable:** The API is entirely composable, giving you great flexibility in how you scrape each page.\n\n- **Pagination support:** Paginate through websites, scraping each page. X-ray also supports a request `delay` and a pagination `limit`. Scraped pages can be streamed to a file, so if there's an error on one page, you won't lose what you've already scraped.\n\n- **Crawler support:** Start on one page and move to the next easily. The flow is predictable, following\n  a breadth-first crawl through each of the pages.\n\n- **Responsible:** X-ray has support for concurrency, throttles, delays, timeouts and limits to help you scrape any page responsibly.\n\n- **Pluggable drivers:** Swap in different scrapers depending on your needs. Currently supports HTTP and [PhantomJS driver](http://github.com/lapwinglabs/x-ray-phantom) drivers. In the future, I'd like to see a Tor driver for requesting pages through the Tor network.\n\n## Selector API\n\n### xray(url, selector)(fn)\n\nScrape the `url` for the following `selector`, returning an object in the callback `fn`.\nThe `selector` takes an enhanced jQuery-like string that is also able to select on attributes. The syntax for selecting on attributes is `selector@attribute`. If you do not supply an attribute, the default is selecting the `innerText`.\n\nHere are a few examples:\n\n- Scrape a single tag\n\n```js\nxray('http://google.com', 'title')(function(err, title) {\n  console.log(title) // Google\n})\n```\n\n- Scrape a single class\n\n```js\nxray('http://reddit.com', '.content')(fn)\n```\n\n- Scrape an attribute\n\n```js\nxray('http://techcrunch.com', 'img.logo@src')(fn)\n```\n\n- Scrape `innerHTML`\n\n```js\nxray('http://news.ycombinator.com', 'body@html')(fn)\n```\n\n### xray(url, scope, selector)\n\nYou can also supply a `scope` to each `selector`. In jQuery, this would look something like this: `$(scope).find(selector)`.\n\n### xray(html, scope, selector)\n\nInstead of a url, you can also supply raw HTML and all the same semantics apply.\n\n```js\nvar html = '\u003cbody\u003e\u003ch2\u003ePear\u003c/h2\u003e\u003c/body\u003e'\nx(html, 'body', 'h2')(function(err, header) {\n  header // =\u003e Pear\n})\n```\n\n## API\n\n### xray.driver(driver)\n\nSpecify a `driver` to make requests through. Available drivers include:\n\n- [request](https://github.com/Crazometer/request-x-ray) - A simple driver built around request. Use this to set headers, cookies or http methods.\n- [phantom](https://github.com/lapwinglabs/x-ray-phantom) - A high-level browser automation library. Use this to render pages or when elements need to be interacted with, or when elements are created dynamically using javascript (e.g.: Ajax-calls).\n\n### xray.stream()\n\nReturns Readable Stream of the data. This makes it easy to build APIs around x-ray. Here's an example with Express:\n\n```js\nvar app = require('express')()\nvar x = require('x-ray')()\n\napp.get('/', function(req, res) {\n  var stream = x('http://google.com', 'title').stream()\n  stream.pipe(res)\n})\n```\n\n### xray.write([path])\n\nStream the results to a `path`.\n\nIf no path is provided, then the behavior is the same as [.stream()](#xraystream).\n\n### xray.then(cb)\n\nConstructs a `Promise` object and invoke its `then` function with a callback `cb`. Be sure to invoke `then()` at the last step of xray method chaining, since the other methods are not promisified.\n\n```js\nx('https://dribbble.com', 'li.group', [\n  {\n    title: '.dribbble-img strong',\n    image: '.dribbble-img [data-src]@data-src'\n  }\n])\n  .paginate('.next_page@href')\n  .limit(3)\n  .then(function(res) {\n    console.log(res[0]) // prints first result\n  })\n  .catch(function(err) {\n    console.log(err) // handle error in promise\n  })\n```\n\n### xray.paginate(selector)\n\nSelect a `url` from a `selector` and visit that page.\n\n### xray.limit(n)\n\nLimit the amount of pagination to `n` requests.\n\n### xray.abort(validator)\n\nAbort pagination if `validator` function returns `true`.\nThe `validator` function receives two arguments:\n\n- `result`: The scrape result object for the current page.\n- `nextUrl`: The URL of the next page to scrape.\n\n### xray.delay(from, [to])\n\nDelay the next request between `from` and `to` milliseconds.\nIf only `from` is specified, delay exactly `from` milliseconds.\n```js\nvar x = Xray().delay('1s', '10s')\n```\n\n### xray.concurrency(n)\n\nSet the request concurrency to `n`. Defaults to `Infinity`.\n```js\nvar x = Xray().concurrency(2)\n```\n\n### xray.throttle(n, ms)\n\nThrottle the requests to `n` requests per `ms` milliseconds.\n```js\nvar x = Xray().throttle(2, '1s')\n```\n\n### xray.timeout (ms)\n\nSpecify a timeout of `ms` milliseconds for each request.\n```js\nvar x = Xray().timeout(30)\n```\n\n## Collections\n\nX-ray also has support for selecting collections of tags. While `x('ul', 'li')` will only select the first list item in an unordered list, `x('ul', ['li'])` will select all of them.\n\nAdditionally, X-ray supports \"collections of collections\" allowing you to smartly select all list items in all lists with a command like this: `x(['ul'], ['li'])`.\n\n## Composition\n\nX-ray becomes more powerful when you start composing instances together. Here are a few possibilities:\n\n### Crawling to another site\n\n```js\nvar Xray = require('x-ray')\nvar x = Xray()\n\nx('http://google.com', {\n  main: 'title',\n  image: x('#gbar a@href', 'title') // follow link to google images\n})(function(err, obj) {\n  /*\n  {\n    main: 'Google',\n    image: 'Google Images'\n  }\n*/\n})\n```\n\n### Scoping a selection\n\n```js\nvar Xray = require('x-ray')\nvar x = Xray()\n\nx('http://mat.io', {\n  title: 'title',\n  items: x('.item', [\n    {\n      title: '.item-content h2',\n      description: '.item-content section'\n    }\n  ])\n})(function(err, obj) {\n  /*\n  {\n    title: 'mat.io',\n    items: [\n      {\n        title: 'The 100 Best Children\\'s Books of All Time',\n        description: 'Relive your childhood with TIME\\'s list...'\n      }\n    ]\n  }\n*/\n})\n```\n\n### Filters\n\nFilters can specified when creating a new Xray instance. To apply filters to a value, append them to the selector using `|`.\n\n```js\nvar Xray = require('x-ray')\nvar x = Xray({\n  filters: {\n    trim: function(value) {\n      return typeof value === 'string' ? value.trim() : value\n    },\n    reverse: function(value) {\n      return typeof value === 'string'\n        ? value\n            .split('')\n            .reverse()\n            .join('')\n        : value\n    },\n    slice: function(value, start, end) {\n      return typeof value === 'string' ? value.slice(start, end) : value\n    }\n  }\n})\n\nx('http://mat.io', {\n  title: 'title | trim | reverse | slice:2,3'\n})(function(err, obj) {\n  /*\n  {\n    title: 'oi'\n  }\n*/\n})\n```\n\n## Examples\n\n- [selector](/examples/selector/index.js): simple string selector\n- [collections](/examples/collections/index.js): selects an object\n- [arrays](/examples/arrays/index.js): selects an array\n- [collections of collections](/examples/collection-of-collections/index.js): selects an array of objects\n- [array of arrays](/examples/array-of-arrays/index.js): selects an array of arrays\n\n## In the Wild\n\n- [Levered Returns](http://leveredreturns.com): Uses x-ray to pull together financial data from various unstructured sources around the web.\n\n## Resources\n\n- Video: https://egghead.io/lessons/node-js-intro-to-web-scraping-with-node-and-x-ray\n\n## Backers\n\nSupport us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/x-ray#backer)]\n\n\u003ca href=\"https://opencollective.com/x-ray/backer/0/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/0/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/1/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/1/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/2/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/2/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/3/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/3/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/4/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/4/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/5/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/5/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/6/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/6/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/7/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/7/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/8/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/8/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/9/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/9/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/10/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/10/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/11/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/11/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/12/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/12/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/13/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/13/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/14/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/14/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/15/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/15/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/16/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/16/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/17/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/17/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/18/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/18/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/19/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/19/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/20/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/20/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/21/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/21/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/22/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/22/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/23/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/23/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/24/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/24/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/25/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/25/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/26/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/26/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/27/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/27/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/28/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/28/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/backer/29/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/backer/29/avatar.svg\"\u003e\u003c/a\u003e\n\n## Sponsors\n\nBecome a sponsor and get your logo on our website and on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/x-ray#sponsor)]\n\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/0/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/0/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/1/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/1/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/2/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/2/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/3/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/3/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/4/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/4/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/5/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/5/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/6/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/6/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/7/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/7/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/8/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/8/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/9/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/9/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/10/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/10/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/11/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/11/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/12/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/12/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/13/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/13/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/14/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/14/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/15/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/15/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/16/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/16/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/17/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/17/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/18/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/18/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/19/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/19/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/20/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/20/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/21/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/21/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/22/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/22/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/23/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/23/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/24/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/24/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/25/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/25/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/26/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/26/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/27/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/27/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/28/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/28/avatar.svg\"\u003e\u003c/a\u003e\n\u003ca href=\"https://opencollective.com/x-ray/sponsor/29/website\" target=\"_blank\"\u003e\u003cimg src=\"https://opencollective.com/x-ray/sponsor/29/avatar.svg\"\u003e\u003c/a\u003e\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatthewmueller%2Fx-ray","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatthewmueller%2Fx-ray","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatthewmueller%2Fx-ray/lists"}