{"id":27048484,"url":"https://github.com/graphcool/chromeless","last_synced_at":"2025-04-05T07:01:51.811Z","repository":{"id":44909684,"uuid":"93076012","full_name":"schickling/chromeless","owner":"schickling","description":"🖥  Chrome automation made simple. Runs locally or headless on AWS Lambda.","archived":true,"fork":false,"pushed_at":"2018-11-13T02:23:55.000Z","size":1088,"stargazers_count":13229,"open_issues_count":198,"forks_count":575,"subscribers_count":228,"default_branch":"master","last_synced_at":"2025-03-29T07:49:59.732Z","etag":null,"topics":["chrome","graphcool","headless","headless-chrome","integration-testing","nightmarejs","selenium","serverless"],"latest_commit_sha":null,"homepage":"https://chromeless.netlify.com","language":"TypeScript","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/schickling.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-01T16:11:11.000Z","updated_at":"2025-03-26T07:51:26.000Z","dependencies_parsed_at":"2022-08-16T04:30:30.362Z","dependency_job_id":null,"html_url":"https://github.com/schickling/chromeless","commit_stats":null,"previous_names":["prisma-archive/chromeless","graphcool/chromeless"],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schickling%2Fchromeless","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schickling%2Fchromeless/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schickling%2Fchromeless/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/schickling%2Fchromeless/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/schickling","download_url":"https://codeload.github.com/schickling/chromeless/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247299829,"owners_count":20916190,"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","graphcool","headless","headless-chrome","integration-testing","nightmarejs","selenium","serverless"],"created_at":"2025-04-05T07:01:32.684Z","updated_at":"2025-04-05T07:01:51.786Z","avatar_url":"https://github.com/schickling.png","language":"TypeScript","readme":"*This project is deprecated in favor for [Puppeteer](https://github.com/GoogleChrome/puppeteer). \nThanks to all the contributors who made this project possible.*\n\n# Chromeless\n\n[![npm](https://img.shields.io/npm/v/chromeless.svg)](https://npmjs.com/package/chromeless)\n[![downloads](https://img.shields.io/npm/dm/chromeless.svg)](https://npmjs.com/package/chromeless)\n[![circleci](https://circleci.com/gh/prismagraphql/chromeless.svg?style=shield)](https://circleci.com/gh/prismagraphql/workflows/chromeless/tree/master)\n[![codecov](https://codecov.io/gh/prismagraphql/chromeless/branch/master/graph/badge.svg)](https://codecov.io/gh/prismagraphql/chromeless)\n[![dependencies](https://david-dm.org/prismagraphql/chromeless/status.svg)](https://david-dm.org/prismagraphql/chromeless)\n[![node](https://img.shields.io/node/v/chromeless.svg)]()\n[![semantic-release](https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg)](https://github.com/semantic-release/semantic-release)\n\nChrome automation made simple. Runs locally or headless on AWS Lambda. (**[See Demo](https://chromeless.netlify.com/)**)\n\n## Chromeless can be used to...\n\n* Run 1000s of **browser integration tests in parallel** ⚡️\n* Crawl the web \u0026 automate screenshots\n* Write bots that require a real browser\n* *Do pretty much everything you've used __PhantomJS, NightmareJS or Selenium__ for before*\n\n### Examples\n\n* [JSON of Google Results](examples/extract-google-results.js): Google for `chromeless` and get a list of JSON results\n* [Screenshot of Google Results](examples/google-screenshot.js): Google for `chromeless` and take a screenshot of the results\n* [prep](https://github.com/prismagraphql/prep): Compile-time prerendering for SPA/PWA (like React, Vue...) instead of server-side rendering (SSR)\n* *See the full [examples list](/examples) for more*\n\n## ▶️ Try it out\n\nYou can try out Chromeless and explore the API in the browser-based **[demo playground](https://chromeless.netlify.com/)** ([source](https://github.com/prismagraphql/chromeless-playground)).\n\n[![](http://i.imgur.com/i1gtCzy.png)](https://chromeless.netlify.com/)\n\n## Contents\n1. [How it works](#how-it-works)\n1. [Installation](#installation)\n1. [Usage](#usage)\n1. [API Documentation](#api-documentation)\n1. [Configuring Development Environment](#configuring-development-environment)\n1. [FAQ](#faq)\n1. [Contributors](#contributors)\n1. [Credits](#credits)\n1. [Help \u0026 Community](#help-and-community)\n\n## How it works\n\nWith Chromeless you can control Chrome (open website, click elements, fill out forms...) using an [elegant API](docs/api.md). This is useful for integration tests or any other scenario where you'd need to script a real browser.\n\n### There are 2 ways to use Chromeless\n\n1. Running Chrome on your local computer\n2. Running Chrome on AWS Lambda and controlling it remotely\n\n![](http://imgur.com/2bgTyAi.png)\n\n### 1. Local Setup\n\nFor local development purposes where a fast feedback loop is necessary, the easiest way to use Chromeless is by controlling your local Chrome browser. Just follow the [usage guide](#usage) to get started.\n\n### 2. Remote Proxy Setup\n\nYou can also run Chrome in [headless-mode](https://developers.google.com/web/updates/2017/04/headless-chrome) on AWS Lambda. This way you can speed up your tests by running them in parallel. (In [Graphcool](https://www.graph.cool/)'s case this decreased test durations from ~20min to a few seconds.)\n\nChromeless comes out of the box with a remote proxy built-in - the usage stays completely the same. This way you can write and run your tests locally and have them be executed remotely on AWS Lambda. The proxy connects to Lambda through a Websocket connection to forward commands and return the evaluation results.\n\n## Installation\n```sh\nnpm install chromeless\n```\n\n### Proxy Setup\n\nThe project contains a [Serverless](https://serverless.com/) service for running and driving Chrome remotely on AWS Lambda.\n\n1. Deploy The Proxy service to AWS Lambda. More details [here](serverless#setup)\n2. Follow the usage instructions [here](serverless#using-the-proxy).\n\n\n## Usage\n\nUsing Chromeless is similar to other browser automation tools. For example:\n\n```js\nconst { Chromeless } = require('chromeless')\n\nasync function run() {\n  const chromeless = new Chromeless()\n\n  const screenshot = await chromeless\n    .goto('https://www.google.com')\n    .type('chromeless', 'input[name=\"q\"]')\n    .press(13)\n    .wait('#resultStats')\n    .screenshot()\n\n  console.log(screenshot) // prints local file path or S3 url\n\n  await chromeless.end()\n}\n\nrun().catch(console.error.bind(console))\n```\n\n### Local Chrome Usage\n\nTo run Chromeless locally, you need a recent version of Chrome or Chrome Canary installed (version 60 or greater). By default, chromeless will start Chrome automatically and will default to the most recent version found on your system if there's multiple. You can override this behavior by starting Chrome yourself, and passing a flag of `launchChrome: false` in the `Chromeless` constructor.\n\nTo launch Chrome yourself, and open the port for chromeless, follow this example:\n\n```sh\nalias canary=\"/Applications/Google\\ Chrome\\ Canary.app/Contents/MacOS/Google\\ Chrome\\ Canary\"\ncanary --remote-debugging-port=9222\n```\n\nOr run Chrome Canary headless-ly:\n\n```sh\ncanary --remote-debugging-port=9222 --disable-gpu --headless\n```\n\nOr run Chrome headless-ly on Windows:\n\n```sh\ncd \"C:\\Program Files (x86)\\Google\\Chrome\\Application\"\nchrome --remote-debugging-port=9222 --disable-gpu --headless\n```\n\n### Proxy Usage\n\nFollow the setup instructions [here](serverless#installation).\n\nThen using Chromeless with the Proxy service is the same as running it locally with the exception of the `remote` option.\nAlternatively you can configure the Proxy service's endpoint with environment variables. [Here's how](serverless#using-the-proxy).\n```js\nconst chromeless = new Chromeless({\n  remote: {\n    endpointUrl: 'https://XXXXXXXXXX.execute-api.eu-west-1.amazonaws.com/dev',\n    apiKey: 'your-api-key-here',\n  },\n})\n```\n\n## API Documentation\n\n**Chromeless constructor options**\n- [`new Chromeless(options: ChromelessOptions)`](docs/api.md#chromeless-constructor-options)\n\n**Chromeless methods**\n- [`end()`](docs/api.md#api-end)\n\n**Chrome methods**\n- [`goto(url: string, timeout?: number)`](docs/api.md#api-goto)\n- [`setUserAgent(useragent: string)`](docs/api.md#api-setUserAgent)\n- [`click(selector: string, x?: number, y?: number)`](docs/api.md#api-click)\n- [`wait(timeout: number)`](docs/api.md#api-wait-timeout)\n- [`wait(selector: string)`](docs/api.md#api-wait-selector)\n- [`wait(fn: (...args: any[]) =\u003e boolean, ...args: any[])`] - Not implemented yet\n- [`clearCache()`](docs/api.md#api-clearcache)\n- [`clearStorage(origin: string, storageTypes: string)`](docs/api.md#api-clearstorage)\n- [`focus(selector: string)`](docs/api.md#api-focus)\n- [`press(keyCode: number, count?: number, modifiers?: any)`](docs/api.md#api-press)\n- [`type(input: string, selector?: string)`](docs/api.md#api-type)\n- [`back()`](docs/api.md#api-back) - Not implemented yet\n- [`forward()`](docs/api.md#api-forward) - Not implemented yet\n- [`refresh()`](docs/api.md#api-refresh) - Not implemented yet\n- [`mousedown(selector: string)`](docs/api.md#api-mousedown)\n- [`mouseup(selector: string)`](docs/api.md#api-mouseup)\n- [`scrollTo(x: number, y: number)`](docs/api.md#api-scrollto)\n- [`scrollToElement(selector: string)`](docs/api.md#api-scrolltoelement)\n- [`setHtml(html: string)`](docs/api.md#api-sethtml)\n- [`setExtraHTTPHeaders(headers: Headers)`](docs/api.md#api-setextrahttpheaders)\n- [`setViewport(options: DeviceMetrics)`](docs/api.md#api-setviewport)\n- [`evaluate\u003cU extends any\u003e(fn: (...args: any[]) =\u003e void, ...args: any[])`](docs/api.md#api-evaluate)\n- [`inputValue(selector: string)`](docs/api.md#api-inputvalue)\n- [`exists(selector: string)`](docs/api.md#api-exists)\n- [`screenshot(selector: string, options: ScreenshotOptions)`](docs/api.md#api-screenshot)\n- [`pdf(options?: PdfOptions)`](docs/api.md#api-pdf)\n- [`html()`](docs/api.md#api-html)\n- [`cookies()`](docs/api.md#api-cookies)\n- [`cookies(name: string)`](docs/api.md#api-cookies-name)\n- [`cookies(query: CookieQuery)`](docs/api.md#api-cookies-query) - Not implemented yet\n- [`allCookies()`](docs/api.md#api-all-cookies)\n- [`setCookies(name: string, value: string)`](docs/api.md#api-setcookies)\n- [`setCookies(cookie: Cookie)`](docs/api.md#api-setcookies-one)\n- [`setCookies(cookies: Cookie[])`](docs/api.md#api-setcookies-many)\n- [`deleteCookies(name: string)`](docs/api.md#api-deletecookies)\n- [`clearCookies()`](docs/api.md#api-clearcookies)\n- [`clearInput(selector: string)`](docs/api.md#api-clearInput)\n- [`setFileInput(selector: string, files: string | string[])`](docs/api.md#api-set-file-input)\n\n## Configuring Development Environment\n\n**Requirements:**\n- NodeJS version 8.2 and greater\n\n1) Clone this repository\n2) Run `npm install`\n3) To build: `npm run build`\n\n#### Linking this NPM repository\n\n1) Go to this repository locally\n2) Run `npm link`\n3) Go to the folder housing your chromeless scripts\n4) Run `npm link chromeless`\n\nNow your local chromeless scripts will use your local development of chromeless.\n\n## FAQ\n\n### How is this different from [NightmareJS](https://github.com/segmentio/nightmare), PhantomJS or Selenium?\n\nThe `Chromeless` API is very similar to NightmareJS as their API is pretty awesome. The big difference is that `Chromeless` is based on Chrome in [headless-mode](https://developers.google.com/web/updates/2017/04/headless-chrome), and runs in a serverless function in AWS Lambda. The advantage of this is that you can run hundreds of browsers in parallel, without having to think about parallelisation. Running integration Tests for example is much faster.\n\n### I'm new to AWS Lambda, is this still for me?\n\nYou still can use this locally without Lambda, so yes. Besides that, here is a [simple guide](https://github.com/prismagraphql/chromeless/tree/master/serverless) on how to set the lambda function up for `Chromeless`.\n\n### How much does it cost to run Chromeless in production?\n\n\u003e The compute price is $0.00001667 per GB-s and the free tier provides 400,000 GB-s. The request price is $0.20 per 1 million requests and the free tier provides 1M requests per month.\n\nThis means you can easily execute \u003e 100.000 tests for free in the free tier.\n\n### Are there any limitations?\n\nIf you're running Chromeless on AWS Lambda, the execution cannot take longer than 5 minutes which is the current limit of Lambda. Besides that, every feature that's supported in Chrome is also working with Chromeless. The maximal number of concurrent function executions is 1000. [AWS API Limits](http://docs.aws.amazon.com/lambda/latest/dg/limits.html)\n\n### Are there commercial options?\n\nAlthough Chromeless is the easiest way to get started running Chrome on Lambda, you may not have time to build and manage your own visual testing toolkit. Commercial options include:\n\n* [Chromatic](http://chromaticqa.com): Visual snapshot regression testing for [Storybook](https://storybook.js.org/).\n\n## Troubleshooting\n### Error: Unable to get presigned websocket URL and connect to it.\nIn case you get an error like this when running the Chromeless client:\n```\n{ HTTPError: Response code 403 (Forbidden)\n    at stream.catch.then.data (/code/chromeless/node_modules/got/index.js:182:13)\n    at process._tickDomainCallback (internal/process/next_tick.js:129:7)\n  name: 'HTTPError',\n...\nError: Unable to get presigned websocket URL and connect to it.\n```\nMake sure that you're running at least version `1.19.0` of [`serverless`](https://github.com/serverless/serverless). It is a known [issue](https://github.com/serverless/serverless/issues/2450), that the API Gateway API keys are not setup correctly in older Serverless versions. Best is to run `npm run deploy` within the project as this will use the local installed version of `serverless`.\n\n### Resource ServerlessDeploymentBucket does not exist for stack chromeless-serverless-dev\nIn case the deployment of the serverless function returns an error like this:\n```\n  Serverless Error ---------------------------------------\n\n  Resource ServerlessDeploymentBucket does not exist for stack chromeless-serverless-dev\n```\nPlease check, that there is no stack with the name `chromeless-serverless-dev` existing yet, otherwise serverless can't correctly provision the bucket.\n\n### No command gets executed\nIn order for the commands to be processed, make sure, that you call one of the commands `screenshot`, `evaluate`, `cookiesGetAll` or `end` at the end of your execution chain.\n\n## Contributors\n\nA big thank you to all contributors and supporters of this repository 💚\n\n\u003ca href=\"https://github.com/joelgriffith/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/joelgriffith.png?size=64\" width=\"64\" height=\"64\" alt=\"joelgriffith\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/adieuadieu/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/adieuadieu.png?size=64\" width=\"64\" height=\"64\" alt=\"adieuadieu\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/schickling/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/schickling.png?size=64\" width=\"64\" height=\"64\" alt=\"schickling\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/timsuchanek/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/timsuchanek.png?size=64\" width=\"64\" height=\"64\" alt=\"timsuchanek\"\u003e\n\u003c/a\u003e\n\n\n\u003ca href=\"https://github.com/Chrisgozd/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/Chrisgozd.png?size=64\" width=\"64\" height=\"64\" alt=\"Chrisgozd\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/criticalbh/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/criticalbh.png?size=64\" width=\"64\" height=\"64\" alt=\"criticalbh\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/d2s/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/d2s.png?size=64\" width=\"64\" height=\"64\" alt=\"d2s\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/emeth-/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/emeth-.png?size=64\" width=\"64\" height=\"64\" alt=\"emeth-\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/githubixx/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/githubixx.png?size=64\" width=\"64\" height=\"64\" alt=\"githubixx\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/hax/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/hax.png?size=64\" width=\"64\" height=\"64\" alt=\"hax\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/Hazealign/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/Hazealign.png?size=64\" width=\"64\" height=\"64\" alt=\"Hazealign\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/joeyvandijk/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/joeyvandijk.png?size=64\" width=\"64\" height=\"64\" alt=\"joeyvandijk\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/liady/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/liady.png?size=64\" width=\"64\" height=\"64\" alt=\"liady\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/matthewmueller/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/matthewmueller.png?size=64\" width=\"64\" height=\"64\" alt=\"matthewmueller\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/seangransee/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/seangransee.png?size=64\" width=\"64\" height=\"64\" alt=\"seangransee\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/sorenbs/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/sorenbs.png?size=64\" width=\"64\" height=\"64\" alt=\"sorenbs\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/toddwprice/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/toddwprice.png?size=64\" width=\"64\" height=\"64\" alt=\"toddwprice\"\u003e\n\u003c/a\u003e\n\u003ca href=\"https://github.com/vladgolubev/\" target=\"_blank\"\u003e\n  \u003cimg src=\"https://github.com/vladgolubev.png?size=64\" width=\"64\" height=\"64\" alt=\"vladgolubev\"\u003e\n\u003c/a\u003e\n\n\n\n\n## Credits\n\n* [chrome-remote-interface](https://github.com/cyrus-and/chrome-remote-interface): Chromeless uses this package as an interface to Chrome\n* [serverless-chrome](https://github.com/adieuadieu/serverless-chrome): Compiled Chrome binary that runs on AWS Lambda (Azure and GCP soon, too.)\n* [NightmareJS](https://github.com/segmentio/nightmare): We draw a lot of inspiration for the API from this great tool\n\n\n\u003ca name=\"help-and-community\" /\u003e\n\n## Help \u0026 Community [![Slack Status](https://slack.graph.cool/badge.svg)](https://slack.graph.cool)\n\nJoin our [Slack community](http://slack.graph.cool/) if you run into issues or have questions. We love talking to you!\n\n\u003cp align=\"center\"\u003e\u003ca href=\"https://oss.prisma.io\"\u003e\u003cimg src=\"https://imgur.com/IMU2ERq.png\" alt=\"Prisma\" height=\"170px\"\u003e\u003c/a\u003e\u003c/p\u003e\n","funding_links":[],"categories":["Automation","TypeScript","Open Source Repos","Deprecated  (a-z↓)","Table of Contents","Browser automation"],"sub_categories":["React Components","Lambda","Automation"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphcool%2Fchromeless","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraphcool%2Fchromeless","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraphcool%2Fchromeless/lists"}