{"id":22021820,"url":"https://github.com/foo-software/binoculars","last_synced_at":"2025-05-07T06:42:26.822Z","repository":{"id":56423844,"uuid":"288051344","full_name":"foo-software/binoculars","owner":"foo-software","description":"A tool to measure web page SEO friendliness","archived":false,"fork":false,"pushed_at":"2020-12-28T18:37:35.000Z","size":2327,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-20T13:19:18.303Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/foo-software.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}},"created_at":"2020-08-17T00:53:38.000Z","updated_at":"2025-02-13T06:34:38.000Z","dependencies_parsed_at":"2022-08-15T18:30:32.882Z","dependency_job_id":null,"html_url":"https://github.com/foo-software/binoculars","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo-software%2Fbinoculars","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo-software%2Fbinoculars/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo-software%2Fbinoculars/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/foo-software%2Fbinoculars/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/foo-software","download_url":"https://codeload.github.com/foo-software/binoculars/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252831097,"owners_count":21810777,"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":[],"created_at":"2024-11-30T06:15:22.991Z","updated_at":"2025-05-07T06:42:26.817Z","avatar_url":"https://github.com/foo-software.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# `@foo-software/binoculars`\n\n\u003cimg alt=\"Binoculars Logo\" align=\"right\" src=\"https://s3.amazonaws.com/foo.software/images/marketing/binoculars.svg\" width=\"20%\" /\u003e\n\nA tool to measure web page SEO friendliness. Binoculars extends [Google's Lighthouse](https://github.com/GoogleChrome/lighthouse) to provide a more opinionated, SEO specific audit.\n\n- Choice of programmatic usage or CLI.\n- Run a single audit or multiple audits at once.\n- Upload reports to S3 via simple configuration.\n- Automatically post results as comments in GitHub via commits or pull requests (see [options](#options)).\n- Automatically post results in Slack (see [options](#options)).\n\n# Meaningful Content\n\nBinoculars extends Lighthouse by adding the following audits in a custom group named \"Meaningful Content\".\n\n- **Title Length**: Title should be between 50 - 70 characters.\n- **Description Length**: Descriptions should be between 100 - 160 characters.\n- **Keywords**: Keyword phrases of at least 2 words should exist in the title, description and at least twice in the content of the page.\n- **Headings**: Has at least 1 `\u003ch1\u003e` tag and 1 `\u003ch2\u003e` tag.\n- **Meaningful Text**: Has sufficient textual content (300 characters).\n- **Meaningful Tag Structure**: Has at least 2 different informational HTML tags of the following types: `\u003cp\u003e`, `\u003cli\u003e`, `\u003cimg\u003e`, `\u003ctable\u003e`.\n\n# Metrics\n\nBinoculars accounts for metrics from Lighthouse SEO and accessibility categories and weights them accordingly. It combines metrics from these categories with the \"Meaningful Content\" group detailed above. See the complete list of audits and weighting [here](src/config/auditRefsConfig.ts).\n\n# Usage\n\nUse programmatically or via CLI.\n\n```\nnpm i @foo-software/binoculars\n```\n\nor\n\n```\nyarn @foo-software/binoculars\n```\n\n## Programmatic Usage\n\n```javascript\nconst path = require('path');\nconst binoculars = require('@foo-software/binoculars').default;\n\n(async () =\u003e {\n  const results = await binoculars({\n    url: 'https://www.foo.software',\n \n    // example if you have an \"artifacts\" directory in your root directory\n    outputDirectory: path.resolve('./artifacts'),\n \n    // any other options go here\n  });\n \n  console.log('local report', results[0].localReport);\n  // local report ./reports/report-1602194942162.html\n\n  console.log('score', results[0].result.categories.binocularsSeo.score);\n  // score 0.96\n})();\n```\n\n## CLI Usage\n\nArguments are represented in the [options section](#options). Any array type relies on the pipe symbol as shown with `urls` in the second example below.\n\n```bash\nbinoculars --url https://www.foo.software --outputDirectory ./artifacts\n```\n\nUse a `|` when auditing multiple URLs like so:\n\n```bash\nbinoculars --urls \"https://www.foo.software|https://www.foo.software/register\"\n```\n\n# Options\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eName\u003c/th\u003e\n    \u003cth\u003eDescription\u003c/th\u003e\n    \u003cth\u003eType\u003c/th\u003e\n    \u003cth\u003eDefault\u003c/th\u003e\n    \u003cth\u003eRequired\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eauthor\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eFor Slack notifications: A user handle, typically from GitHub.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eawsAccessKeyId\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe AWS \u003ccode\u003eaccessKeyId\u003c/code\u003e for an S3 bucket.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eawsBucket\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe AWS \u003ccode\u003eBucket\u003c/code\u003e for an S3 bucket.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eawsRegion\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe AWS \u003ccode\u003eregion\u003c/code\u003e for an S3 bucket.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eawsSecretAccessKey\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe AWS \u003ccode\u003esecretAccessKey\u003c/code\u003e for an S3 bucket.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003ebranch\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eFor Slack notifications: A version control branch, typically from GitHub.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003ecommentAccessToken\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ca href=\"https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line\"\u003eAccess token\u003c/a\u003e of a user to post PR comments.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003ecommentUrl\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eAn endpoint to post comments to. Typically this will be from \u003ca href=\"https://developer.github.com/v3/pulls/reviews/#create-a-pull-request-review\"\u003eGitHub's API\u003c/a\u003e. Example: \u003ccode\u003ehttps://api.github.com/repos/:owner/:repo/pulls/:pull_number/reviews\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eenableComments\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eIf \u003ccode\u003etrue\u003c/code\u003e and \u003ccode\u003ecommentAccessToken\u003c/code\u003e is set along with \u003ccode\u003ecommentUrl\u003c/code\u003e, scores will be posted as comments.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eboolean\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003etrue\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003efinalScreenshotAwsBucket\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe AWS \u003ccode\u003eBucket\u003c/code\u003e for an S3 bucket. If this is defined, the final screenshot will be uploaded here\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eminScore\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe required minimum score. If score is lower an error will throw.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003enumber\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003c!-- \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003elocale\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eA locale for Lighthouse reports. Example: \u003ccode\u003eja\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e --\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eoutputDirectory\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eAn absolute directory path to output report. You can do this an an alternative or combined with an S3 upload.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003epr\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eFor Slack notifications: A version control pull request URL, typically from GitHub.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eslackWebhookUrl\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eA Slack Incoming Webhook URL to send notifications to.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003esha\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eFor Slack notifications: A version control \u003ccode\u003esha\u003c/code\u003e, typically from GitHub.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eno\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eurl\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eA URL to run Binoculars against.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eyes\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eurls\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eAn array of URLs. In the CLI this value should be a pipe separated list (\u003ccode\u003e|\u003c/code\u003e).\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring[]\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eundefined\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eyes\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n# Return Payload\n\n`binoculars` is a promise that resolves an array. The reason it resolves with an array is because options allow `url` or `urls`. Because a consistent return is ideal, we return an array regardless if there is only one result or more. Each array item is an object with the below payload.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eName\u003c/th\u003e\n    \u003cth\u003eDescription\u003c/th\u003e\n    \u003cth\u003eType\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003efinalScreenshot\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eA URL to the final screenshot image. This will only be defined if \u003ccode\u003efinalScreenshotAwsBucket\u003c/code\u003e parameter was.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003elocalReport\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eA local path to the report (if applicable).\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eresult\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eA comprehensive result - the equivalent of what is returned when using the \u003ccode\u003elighthouse\u003c/code\u003e module directly.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003eobject\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003ereport\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eA URL to the report HTML file.\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003estring\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n# Environment Variables\n\nYou can optionally provide environment variables as detailed below.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eName\u003c/th\u003e\n    \u003cth\u003eDescription\u003c/th\u003e\n    \u003cth\u003eType\u003c/th\u003e\n    \u003cth\u003eDefault\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eBINOCULARS_CHROME_PORT\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe port for Chrome to run audits on.\u003c/td\u003e\n    \u003ctd\u003enumber\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e4000\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eBINOCULARS_INTEGRATION_SERVER_DOMAIN\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eDomain of the integration server.\u003c/td\u003e\n    \u003ctd\u003estring\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003elocalhost\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eBINOCULARS_INTEGRATION_SERVER_PORT\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003ePort to run the integration server on.\u003c/td\u003e\n    \u003ctd\u003enumber\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003e3000\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eBINOCULARS_INTEGRATION_SERVER_PROTOCOL\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eProtocol of the integration server.\u003c/td\u003e\n    \u003ctd\u003estring\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003ehttp\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003eLOG_LEVEL\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eThe Winston log level (use \"off\" to run without logging).\u003c/td\u003e\n    \u003ctd\u003estring\u003c/td\u003e\n    \u003ctd\u003e\u003ccode\u003einfo\u003c/code\u003e\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## Credits\n\n\u003e \u003cimg src=\"https://lighthouse-check.s3.amazonaws.com/images/logo-simple-blue-light-512.png\" width=\"100\" height=\"100\" align=\"left\" /\u003e This package was brought to you by [Foo - a website quality monitoring tool](https://www.foo.software). Automatically test and monitor website performance, SEO and accessibility with Lighthouse. Analyze historical records of Lighthouse tests with automated monitoring. Report with confidence about SEO and performance improvements to stay on top of changes when they happen!\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoo-software%2Fbinoculars","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffoo-software%2Fbinoculars","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffoo-software%2Fbinoculars/lists"}