Triggering explorations from any CI
Triggering explorations from any CI
Duku's GitHub Actions are thin wrappers around our Platform API. If your pipelines run somewhere else - CircleCI, Jenkins, GitLab CI, Buildkite - you can make the same API calls directly with curl. This page walks through the complete flow, with CircleCI as the worked example.
Using GitHub Actions? Use the Duku
previeworenvironmentactions instead - they implement everything on this page for you.
What you will set up:
Exchange your Duku API key for a short-lived access token.
Preview flow - register a per-PR build and start an exploration against its preview deployment.
Environment flow - start an exploration and test-case run against a long-lived environment target.
Get results posted back to your GitHub pull requests via the Duku AI GitHub App.
Optionally, block your pipeline until the exploration finishes.
Status. This API surface is the same one our published actions are built on. Like the actions, it is pre-release - operation and field names are stable in practice but may evolve before 1.0.
Endpoints
Token endpoint
https://auth.duku.ai/realms/duku/protocol/openid-connect/token
Platform API (GraphQL)
https://platform.duku.ai/graphql
All Platform API operations are GraphQL: POST a JSON body of the form {"query": "...", "variables": {...}} with an Authorization: Bearer <token> header.
Prerequisites
A Duku API key. Generate one in Viewport → Settings → API Keys. The key is shown once - store it as a secret in your CI. In CircleCI, put it in a context as
DUKU_API_KEY.Preview flow: your product ID (Viewport → Products).
Environment flow: a pre-created environment target ID (created in Viewport).
Your exploration must be set up in Viewport first. If a target has no exploration configured,
startExplorationreturns an error describing what is missing - complete the setup in Viewport and retry.curlandjqin your job image. CircleCI'scimg/baseimage includes both.For PR comments: the Duku AI GitHub App installed on your repository (next section).
Tip. You can list your products over the API with
query { subjects { id name } }- products are called "subjects" in the API schema.
Install the Duku AI GitHub App
When you pass a repository and pull-request number with an exploration, Duku posts a sticky comment on that PR - first "exploration in progress", then updated in place with the results once the exploration finishes. Those comments are posted by the Duku AI GitHub App, so you never need to handle a GitHub token in your CI job.
Open github.com/apps/duku-ai.
Click Install (or Configure if your organisation already has it) and choose the GitHub organisation that owns your repositories. If you are not an organisation owner, GitHub forwards the request to one for approval.
Choose Only select repositories and pick the repositories whose pull requests should receive Duku comments (or All repositories).
Accept the requested permissions - the app only needs to read and write pull-request comments.
That's it. There is nothing to configure on the Duku side: the platform discovers the installation automatically from the repository you name in the API call.
If the app is not installed, explorations still run normally - you just won't get PR comments. Results remain available in Viewport.
Step 1 - Exchange your API key for an access token
See API Keys for how keys work and how to exchange one for an access token. In short: the key is a base64-encoded clientId:clientSecret pair; decode it, split on the first :, and use the standard OAuth2 client-credentials grant to get a short-lived access token.
Save the following helpers to scripts/duku-lib.sh in your repository - the rest of this page builds on them:
Important. Access tokens are short-lived (about 5 minutes). Don't fetch one token at the top of a long job and reuse it -
duku_gqlabove fetches a fresh token per call, which is the simplest safe pattern.
Important. GraphQL errors come back with HTTP status 200, so a bare
curl -fwill not catch them. Always check the response for anerrorsarray, asduku_gqldoes.
A word on hygiene: treat the API key and access tokens as secrets. Avoid set -x in steps that call these helpers, and never echo the token.
Avoid sending passwords in the request body. Instead of passing raw login credentials inline, create a credential set once in Viewport and pass its ID or name as credentialSetId on startExploration or runAllTestCases. Duku decrypts it server-side, so the secret never travels through your CI logs or the GraphQL request.
Adapting the scripts to your CI
The helper scripts on this page use CircleCI environment variable names (CIRCLE_*) as examples. If you run a different CI, substitute your provider's equivalents - the GraphQL calls and the rest of each script stay exactly the same.
Repository (owner/repo)
$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME
$GITHUB_REPOSITORY
$CI_PROJECT_PATH
derive from $GIT_URL, or set manually
Pull / merge request number
parsed from $CIRCLE_PULL_REQUEST (or $CIRCLE_PR_NUMBER)
github.event.pull_request.number
$CI_MERGE_REQUEST_IID
$CHANGE_ID
Commit SHA
$CIRCLE_SHA1
$GITHUB_SHA
$CI_COMMIT_SHA
$GIT_COMMIT
Branch name
$CIRCLE_BRANCH
$GITHUB_HEAD_REF (PRs) / $GITHUB_REF_NAME
$CI_COMMIT_REF_NAME
$BRANCH_NAME
Build number
$CIRCLE_BUILD_NUM
$GITHUB_RUN_NUMBER
$CI_PIPELINE_IID
$BUILD_NUMBER
Build / job URL
$CIRCLE_BUILD_URL
$GITHUB_SERVER_URL/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID
$CI_JOB_URL
$BUILD_URL
Flow A - preview deployments
Two API calls per pipeline, run after your preview deploy step:
upsertSimulationTargetregisters the build as a target under your product. ThebuildKeydeduplicates reruns - every pipeline on the same PR updates the same target instead of creating a new one.startExplorationstarts the exploration against the preview URL. PassinggithubRepository,githubPrNumber, andserverManagedComment: truemakes Duku post and maintain the PR comment for you.
Unlike the GitHub Action - which discovers the preview URL from the GitHub Deployments, Checks, and Statuses APIs - your CI job supplies the preview URL directly. Your deploy step already knows it: vercel deploy prints it, netlify deploy --json returns it as deploy_url, or you may construct it from the PR number.
The exploration runs asynchronously - the script exits in seconds and results appear in Viewport and on the PR comment when the run finishes (typically 5 to 40 minutes).
If one pull request triggers explorations for several products, each product gets its own PR comment.
Vercel Deployment Protection. If your previews are protected, pass the bypass secret when registering the build. Add
--arg bypass "$VERCEL_AUTOMATION_BYPASS_SECRET"to the firstjqcall andmetadata: {vercelAutomationBypassSecret: $bypass}to its input object.
Not on a PR? For pushes without a pull request, use
buildKey: "github:repo=${REPO}:sha=${CIRCLE_SHA1}"and omitgithubRepository,githubPrNumber, andserverManagedComment- there is no PR to comment on.
Keep the github:repo=... buildKey convention shown above even though you're not on GitHub Actions: it matches what the Duku GitHub Actions generate, so if you ever run both, they deduplicate onto the same targets.
For the full list of input fields on upsertSimulationTarget and startExploration, see the GraphQL API reference.
Flow B - environment deployments
For a staging environment, prod canary, or any pre-created environment target: skip target registration and start the run directly, then trigger the target's test cases.
PR-gate mode: to run this against a fixed environment as a pull-request check and get the PR comment, add
githubRepository,githubPrNumber, andserverManagedComment: trueto thestartExplorationinput, exactly as in the preview flow.runAllTestCasesplans the test runs synchronously and can take up to ~90 seconds to respond; the runs themselves then execute asynchronously.
Gate your pipeline on the result
Both flows are async by design: they kick off the run and exit, and results arrive in Viewport and the PR comment. If you want the CircleCI job to pass or fail with the exploration instead, poll the batch status. Add to scripts/duku-lib.sh:
Usage after either flow script:
pendingandrunningare in-flight;completedandfailedare terminal.Explorations typically take 5 to 40 minutes - set the step timeout accordingly (the loop prints a line every 30 seconds, so CircleCI's no-output timeout won't trip).
Polling keeps a CircleCI executor occupied for the whole run. If you only need the results, skip the gate and let the PR comment deliver them.
Putting it together in CircleCI
Store DUKU_API_KEY (and DUKU_PRODUCT_ID or DUKU_TARGET_ID) in a context named duku under Organization Settings → Contexts, then:
Note. CircleCI only populates
CIRCLE_PULL_REQUEST/CIRCLE_PR_NUMBERwhen the pipeline is associated with a pull request. If those are empty on your PR pipelines, check Project Settings → Advanced → Only build pull requests, or pass the PR number into the script yourself.
Troubleshooting
Token request fails with HTTP 401 (invalid_client). The API key is malformed, revoked, or expired. Check that the secret contains the full base64 string from Viewport with no line breaks, or generate a new key in Viewport → Settings → API Keys.
Authentication required in a GraphQL error. The access token expired mid-job - tokens last about 5 minutes. Fetch a fresh token per call (the duku_gql helper does this) rather than reusing one.
Exploration setup error. The product or target has not been set up for exploration yet. Complete its setup in Viewport, then retry.
Not found when referencing a target or product. The ID is wrong, or it belongs to a different organisation - API keys only see resources in the organisation they were created in.
The PR comment never appears. Verify the Duku AI GitHub App is installed on the repository, that githubRepository is exactly owner/repo, and that githubPrNumber is an integer. The results comment posts only when the run finishes - check its status in Viewport if you're unsure whether it's still running.
Duku's agents can't reach your preview. If your site sits behind a firewall, WAF, or bot protection, see Firewall & WAF Allowlisting. For protected Vercel previews, use the Deployment Protection bypass described above.
Need help? If anything on this page doesn't work for your setup, or you're integrating a CI provider with quirks we haven't covered, contact your Duku account team.
Last updated

