Skip to content

Search PixyScan

Guide contents

User guide15 min

Connect your CI/CD pipeline

Add one step to the end of your pipeline. After every deploy, PixyScan scans the address you just released, prints the health score in your build log, and fails the build if the score drops below the number you choose. Setting it up takes about 15 minutes.

Before you start#

Check these four things first. Each one is a common reason a first run fails.

You needWhere to checkWhat it does
A Basic, Pro or Enterprise planBillingOn Free and Hobby the CLI & CI/CD tab shows a lock. See Billing to change your plan.
Admin access to the siteMembersOnly a site's admins can see the CLI & CI/CD tab. Workspace admins are admins of every site. If you are not one, ask an admin to give you the role, or to follow steps 1 to 4 for you. See Members and roles.
The site added to PixyScanWorkspace overviewThe pipeline scans a site you already added. If you have not added it yet, see Add a site.
A pipeline that deploys your siteYour CI providerAny CI that can run Node.js 18 or later. This page covers GitHub Actions, GitLab CI, Bitbucket Pipelines, CircleCI and Jenkins.

How it works, in plain words. Your pipeline (CI/CD) already builds your site and puts it live. You add one more step at the end. That step runs a small program called the PixyScan CLI. The CLI tells PixyScan which branch was just deployed. PixyScan scans the address that branch lives at, and the CLI prints the result in your build log.

If the health score is lower than the number you chose, called the score gate, the CLI ends with exit code 1. Every CI treats an exit code other than 0 as a failed step, so the build stops. Nothing is changed on your site, and nothing comments on your pull requests. The build log and the exit code are the whole result.

Plan
Basic, Pro or Enterprise
Needs
Node.js 18 or later in the CI job
Uses
One URL credit per page scanned, like any scan
Waits
Up to 5 minutes for the scan, unless you change it

Step 1: Create the client secret#

The client secret is a password that proves your pipeline is allowed to scan this site. Each site has its own.

  1. 1

    Open the site's CLI & CI/CD settings

    Open the site in PixyScan. In the sidebar, choose Settings under Manage, then open the CLI & CI/CD tab.

  2. 2

    Press Create the secret

    It is on the Client secret card. A window opens with your new secret. It starts with sk_live_, followed by a long string of letters and numbers.

  3. 3

    Press Copy

    This is the only time the secret is shown. PixyScan keeps only a one-way fingerprint of it, so nobody can show it to you again, our support team included.

    Go straight on to step 2 and save it in your CI. If you need a minute, paste it into a password manager, not into a chat, an email or a file in your repository.

  4. 4

    Press I have stored it, close

    The button only works once you have copied the secret. The card now shows the start of the secret, when it was created, and when a pipeline last used it. Until your first run, Last used says Never.

app.pixyscan.com/w/…/s/…/settings?tab=sdk

The CLI and CI/CD tab: the site's client secret and the list matching branches to environment URLs.
The CLI & CI/CD tab: the client secret at the top, and the list of branches and the URL each one scans.

Lost the secret, or shared it by mistake?

Press Regenerate, then Replace the secret, and save the new one in your CI. The old secret stops working at once, so any pipeline still using it fails with Invalid client secret (401) until it has the new one. Delete removes the secret without making a new one.

Step 2: Save the secret in your CI#

Never paste the secret into a YAML file or commit it to your repository. Every CI has a private store for secrets. Save it there, named PIXYSCAN_SECRET.

Your CIWhere to add itWhat it does
GitHub ActionsRepository → Settings → Secrets and variables → ActionsPress New repository secret. Type PIXYSCAN_SECRET as the name, paste the secret as the value, and press Add secret.
GitLab CIProject → Settings → CI/CD → VariablesPress Add variable. Type PIXYSCAN_SECRET as the key, paste the secret as the value, and make it masked, so it never shows in a job log. Leave Protect variable off unless every branch you scan is protected, because GitLab only gives protected variables to protected branches.
Bitbucket PipelinesRepository settings → Pipelines → Repository variablesType PIXYSCAN_SECRET as the name, paste the secret as the value, tick Secured, and press Add.
CircleCIProject settings → Environment VariablesPress Add Environment Variable. Type PIXYSCAN_SECRET as the name, paste the secret as the value, and confirm.
JenkinsManage Jenkins → CredentialsAdd a credential of the kind Secret text and paste the secret into it. Give it an ID you will recognise, such as pixyscan-secret.
Any other CIIts secrets or variables pageSave it as a secret (masked) environment variable named PIXYSCAN_SECRET.

Menus in these tools change from time to time. If one does not match, look for Secrets or Variables in your project's settings.

The name is up to you, as long as your pipeline step in step 5 uses the same one. This page uses PIXYSCAN_SECRET.

The secret has to be passed to the CLI

The CLI does not find the secret by itself. Your pipeline step has to hand it over. Saving the variable on its own is not enough.

Step 3: Tell PixyScan which address each branch deploys to#

Your pipeline only sends PixyScan a branch name. This list tells PixyScan which address to scan for it, so a build of your staging branch scans your staging site, not your live one.

Your production branch always scans the site's own URL, the one you entered when you added the site. Every other branch you deploy needs an environment: a name, a branch and the address that branch is deployed to. If you only deploy one branch, check the production branch and go on to step 4.

  1. 1

    Check the production branch

    On the Production branch and the gate card, make sure Production branch is the branch that deploys your live site, such as main or master. If you change it, press Save settings.

  2. 2

    Press Add environment

    It is on the Which URL each branch scans card. Add one environment for each other branch you deploy, such as staging or a preview branch.

  3. 3

    Fill in the three fields

    Name is a label, such as Staging. It is shown in scan history and in the report the CLI prints.

    Branch is the branch name, such as develop, or a pattern, such as release/*.

    URL to scan is the address that branch is deployed to, such as https://staging.example.com. PixyScan must be able to reach it from the internet, so private and local addresses are refused. If the site is behind a password, add its sign-in details on the Crawl tab. See Site settings.

  4. 4

    Press Add environment to save it

    It appears as a row in the table. A site can have up to 20 environments. To change one later, edit its row and press Save environment.

How PixyScan matches the branch your pipeline sends to an environment.
Branch ruleExampleWhat it does
Exact namedevelopMatches only the branch called develop. An exact name always wins over a pattern.
Patternrelease/** stands for any text, and it is the only wildcard. release/* matches release/2.4 and release/spring. When two patterns match, the more specific one wins.
No match-The run stops with exit code 2 and a message naming the branch. Add an environment for it, or have the pipeline send a branch that has one.

Preview addresses that change on every build

Some hosts give each pull request its own address. For that environment, turn on Let the pipeline override this URL, then have your pipeline send the address with each run. Only turn it on if you need it: anyone with the client secret can then scan any public address, using this site's credits. The production branch always scans the site's own URL, and ignores an address sent this way.

Building from a Git tag?

On GitHub Actions and GitLab CI, a build started by pushing a tag sends the tag, such as v2.4.0, as its branch. Add an environment with the pattern v*, or have that job send main as its branch.

Step 4: Choose when a build should fail#

Two settings decide it: the lowest health score you accept, and an optional list of checks that must never fail.

  1. 1

    Find today's score

    Open the site's Overview and note the health score of the latest scan, for example 82.

  2. 2

    Type it in Score gate and press Save settings

    Score gate is on the Production branch and the gate card. It takes a whole number from 0 to 100. A scan passes when its score is the same as the gate or higher.

  3. 3

    Optional: add checks that fail the build

    Under Checks that fail the build, open Add a check… and choose one, such as Broken internal links and pages. If a scan finds that check on any page, the build fails, whatever the score. The list saves as soon as you change it. Leave it empty to fail on the score alone.

  4. 4

    Optional: exempt some pages from a check

    Press the pencil on the check's row. Type a part of an address, such as /legacy/, or a pattern, such as /blog/*, and press Enter. Press Save exemptions when the list is done.

    Exemptions only change the build. The problem is still reported on those pages in the app, and still counts towards the health score.

Change the default of 97

Every site starts with a score gate of 97 out of 100, so your first build will probably fail. Set it to today's score, then raise it as you fix things. The same number decides when the Score below threshold alert appears in the app.

Step 5: Add PixyScan to your pipeline#

Add one PixyScan step to your pipeline. It must run after your deploy step, because PixyScan scans the live address, not your code.

Put the PixyScan step after the step that deploys your site, and give it the secret you saved in step 2. Find your CI below.

GitHub Actions. Add the step to the job that deploys your site, after the deploy and after a step that sets up Node.js. To watch it, open the repository's Actions tab and choose the run.

GitLab CI. Add a stage after your deploy stage. Stages run in order, so the scan starts only once the deploy has finished. GitLab gives every job the variables you saved, so there is nothing else to add. To watch it, open Build → Pipelines in the project and choose the PixyScan job.

Bitbucket Pipelines. Add a step after the deploy step. Steps run one after the other. By default the step runs on every branch, so limit it to the branches you deploy if you only want to scan those.

CircleCI. Add a job for the scan, and make it wait for the deploy job to finish.

Jenkins and other CIs. It works on any CI with Node.js 18 or later. The CLI reads the branch by itself only on GitHub Actions, GitLab CI, CircleCI, Bitbucket Pipelines and Vercel. Anywhere else it assumes main, so send the branch, and the commit, yourself. On Jenkins, add a stage after your deploy stage, in a multibranch pipeline whose agent has Node.js, and read the secret from the credential you saved in step 2.

Every run uses credits

A scan from your pipeline uses one URL credit per page, like any other scan. Running it on every push to every branch adds up quickly, so run it on the branches you deploy. Check your credits on Billing.

Step 6: Run it and read the result#

Push a commit to start your pipeline, then open the PixyScan step's log.

While the scan runs, the log shows progress lines that start with [pixyscan-sdk]: Starting scan, Crawling pages with a count of pages, Analysing results, and finally Scan complete. How long it takes depends on how many pages the scan covers.

When it finishes, the CLI prints the PixyScan SEO Scan Report:

LineExampleWhat it does
StatusPASSEDPASSED or FAILED. This is the line to look at first.
BranchdevelopThe branch the run used.
Commita1b2c3dThe commit that was deployed. On a tag build it also shows the release, such as v2.4.0.
EnvironmentStaging (preview)The environment the branch matched in step 3.
URLhttps://staging.example.comThe address that was scanned.
Health score84 / 100The score of this scan. n/a means the scan could not crawl the address.
Threshold82The score gate it was compared with.
Issues37 totalHow many problems were found, with a line each for Critical, Important and Standard.
Suggestions12How many suggestions were found. Suggestions never fail a build.
Must not fail2 checksEach check from your list in step 4, with ✓ if it was not found and ✗ if it was.

The report gives counts, not the list of problems. To see each problem, open the site in PixyScan. The scan is in Scan history with the trigger CLI, named CI/CD Scan followed by the environment, the branch and the time. Then work through it from Issues, the same as any other scan.

The number the CLI ends with. Only 1 means your site got worse. 2 and 3 mean the check itself could not run.
FieldExit codeWhat it does
Passed0The score met the score gate, and no check on your list was found. The build carries on.
Gate failed1The score is below the gate, a check on your list was found, or the scan could not crawl the address. The report says which. This is the code that should stop a release.
Setup problem2Something in the setup is wrong: a missing or wrong secret, a branch with no environment, a plan without the CLI, an unknown check name, or a bad settings file. Fix it with the table under Troubleshooting and run it again.
Could not finish3PixyScan could not be reached, the scan did not finish in time, the workspace is out of URL credits, or another scan of this site is already running. Retry the step once the cause is cleared.

Optional: keep the gate rules in your repository#

A file called pixyscan-settings.json lets your pipeline set its own score gate and list of checks, reviewed in pull requests like the rest of your code.

Put the file in the folder your pipeline step runs from, which is usually the top folder of your repository. The CLI finds it by itself and prints Using pixyscan-settings.json in the log.

pixyscan-settings.json

{
  "version": 1,
  "minScore": 85,
  "failOnIssues": [
    "Broken internal links and pages",
    {
      "issue": "Pages with no canonical tag",
      "excludePages": ["/legacy/*"]
    }
  ]
}
FieldIf you leave it outWhat it does
versionMust be 1The format of the file. Always 1.
minScoreThe site's score gateThe lowest health score that passes, a whole number from 0 to 100.
failOnIssuesThe site's listUp to 200 checks that fail the build when found. Write each one by its title, as the app shows it. To exempt pages from one, write it as an object with issue and up to 50 excludePages, as in the example.

Each value in the file replaces the site's setting for that run only. The list replaces the site's list as a whole: the two are not merged. A check title PixyScan does not recognise stops the run with exit code 2 and suggests the closest name.

Never put the secret in this file

The file is committed to your repository, where anyone who can read the code can read it. The CLI refuses a settings file that has a secret or token in it.

Optional: record which commit was deployed#

Each scan from your pipeline can be labelled with the commit it ran for. On most CIs this happens by itself.

The CLI reads the commit on GitHub Actions, GitLab CI, Bitbucket Pipelines, CircleCI, Vercel and Netlify, with a link to it where the CI gives one. A tag build is also labelled with its tag, such as v2.4.0. The label is information only: it never changes the scan or whether the build passes.

With Search Console connected, each deploy of your production branch is marked on the site's clicks trend with its commit. If clicks drop sharply in the 3 days after a deploy, you get an alert. See Search impact.

Troubleshooting#

Find the message from your build log, then do what the last column says.

The log saysExit codeWhat it does
A client secret is required.2The secret did not reach the CLI. Check that the name in your CI's secrets and the name your pipeline step uses are exactly the same. On GitLab, check the variable is not protected while the branch is not.
Client secret should start with sk_live_ or sk_test_2Something other than the secret was saved. Copy it again with no spaces or quotes around it. If you no longer have it, regenerate it in step 1.
Invalid client secret (401)2The secret was regenerated or deleted after you saved it. Create or regenerate it, and save the new one in your CI.
No environment is configured for branch …2Add an environment for that branch in step 3, or have the pipeline send a branch that has one. On a tag build, see the note in step 3.
CLI access is not included in your plan.2The workspace is on Free or Hobby. Move it to Basic or above on Billing.
This workspace has used all … URLs included in the … plan3The workspace has no URL credits left this period. Add credits or change plan on Billing, or scan fewer branches.
A scan is already running for this site.3A site scans one at a time. Wait for the running scan to finish, then run the step again. A run that timed out earlier leaves its scan running, so this often follows a timeout.
The step timed out3The scan took longer than the timeout. Raise the timeout, or lower the page budget on the Crawl tab of Site settings. The scan carries on in PixyScan, and its results appear in the app.
You cancelled the scan in the app3The CLI keeps waiting until the timeout, then stops. Run the step again when you are ready.
Health score n/a1The scan could not crawl the address. Check it is live and public, then open the scan in the app to see why.

Does something here not match what you see in the app? Tell us