Documentation
Ripplo reviews your pull requests. Run one command, comment @ripplo review on a pull request, and it tests your preview environment and reports what broke.
Using Ripplo
Choose New review from Reviews to check a pull request or create and update coverage. You can also comment @ripplo review on a pull request.
Pull request reviews
A pull request review runs the existing tests against the preview and investigates the behavior changed by the diff. It reports issues with replays and shows the regression results after any fixes to the tests. Those fixes stay with the review. Coverage reviews update the shared tests after changes merge.
Updating tests
Choose New review → Coverage from Reviews. Describe an area to cover, or leave the brief empty for Ripplo to choose. The review checks and repairs existing tests, then adds coverage against the selected app version. Shared tests update when the review finishes successfully.
Debugging a failure
When a step fails, the replay shows the DOM, network, console, and application state at that moment. Copy for agent copies a command that hands the review to your coding agent.
Syncing issues to GitHub or Linear
In the project's settings, open Project context. Under GitHub issues or Linear issues, choose a repository or team to sync Ripplo findings to. A project syncs to one place at a time, and the repository or workspace must be a context source for the project. Each issue Ripplo finds after that opens a matching issue there within a minute, with the same title and description plus a link back to Ripplo. An issue closed before then is skipped until it reopens. Closing or reopening the issue on either side updates the other.
A Linear workspace connected for context can read issues. Choose Allow in Linear to let Ripplo create and update issues in it. Once allowed, Linear keeps that access until the workspace is disconnected. Turning sync off keeps existing links and stops updates. A new destination applies only to issues found after the change.
Coding agents
The Ripplo plugin for Claude Code lets your agent act on a review. /ripplo:review fixes the issues a review found, or one issue when you add issue and its number. /ripplo:cover changes your app so Ripplo can test the workflows a review could not cover. Copy for agent, on a review or an issue, copies the right command.
Setup installs the plugin when Claude Code is installed. To install it yourself, run these two commands.
claude plugin marketplace add ripplo/claude-plugin
claude plugin install ripplo@ripploOther coding agents can use the ripplo command directly, the same way the plugin does. Sign in once, then pull the published issues and uncovered workflows of a review, the failures of a run with nearby evidence, or a snapshot of one frame. Your deploy pipeline can also report which commit is live on an environment.
npx ripplo login # sign in through your browser
npx ripplo logout
npx ripplo review start <prUrl> # review the pull request's latest commit
npx ripplo review status <codeReviewId> # where the review is and which commit it reviewed (JSON)
npx ripplo review <codeReviewId> # published issues and uncovered workflows (JSON)
npx ripplo explain <runId> # failures per step with nearby evidence (JSON)
npx ripplo snapshot <runId> --offset <ms> # PNG and rrweb-tagged HTML of that frame
RIPPLO_TOKEN=<deploy token> npx ripplo deploy \
--environment <name> --sha <sha> # report a deployment from your pipelineCore concepts
What the words in the dashboard mean.
Organizations and projects
An organization is your team's Ripplo workspace, sharing projects, reviewers, runs, and billing. A project maps to one GitHub repository, and Ripplo reviews the pull requests opened against it.
Workflows
A workflow is one thing a user does, written as a click path: go to a page, click, fill, and at each step the checks that must hold on the screen and in your app's data. Ripplo writes and owns them. A workflow can be tested from more than one starting point.
Test data
Date-dependent data, like a payroll due on a given day, is created the same way as any other test data. Ripplo does not simulate the passage of time or run tests that last for hours. If Ripplo cannot create the data a workflow needs, it warns you and asks either for test data or for an API it can use.
How Ripplo creates and removes test data, on the security page
Runs and replays
A run is one execution of a test against the preview environment you pointed Ripplo at. Every run records the pages as rendered, network calls, console output, and the application state checks at each step, and you scrub through it step by step in the dashboard.
Setup
Ripplo tests a deployed copy of your app, such as a staging server or pull request previews. It must be reachable over the internet, and Ripplo will create and change data in it. Do not connect a production environment.
You can set up from the terminal or in the dashboard. Both sign you in with GitHub, and your first sign-in creates your account and an organization.
Create the project
Run setup in your repository. It signs you in, creates the project, and connects the repository to GitHub if it is not connected yet. It then asks for your app's URL, whether to review a staging server, pull request previews, or both, and what your app signs in with.
Next, it prints three values for your app and waits while you do the next step. Then it asks for the callback your auth provider shows for Ripplo and your sign-in page.
npx ripplo setupAdd sign in with Ripplo to your app
Ripplo signs in to your app as an identity provider, the same way sign in with Google works. Add a provider with id ripplo and the scopes openid email profile ripplo to your auth library, using the three values from the connection. Set them as variables where your app runs, then deploy. The client secret is shown once, when the connection is created. If you lose it, rotate it in the project's settings to get a new one.
Each run signs in as a new user, ripplo-<run id>@test.ripplo.ai, so your app must create the user on first sign-in.
Your app also needs a sign-in page: an address that starts sign in with Ripplo as soon as it opens, or a login page that shows one button or link with Ripplo in its text or attributes, which Ripplo clicks. Setup asks for this address after you add the provider.
RIPPLO_IDP_CLIENT_ID=<client id>
RIPPLO_IDP_CLIENT_SECRET=<client secret>
RIPPLO_IDP_DISCOVERY_URL=<discovery URL>The redirect URI on the connection must equal your auth provider's callback address for Ripplo. Setup asks for it after you add the provider. You can change it later in the project's environment settings.
Examples for common auth libraries.
better-auth
In Ripplo
- Run npx ripplo setup, or open the project's settings, choose Environment, then Sign-in connections, then Add connection, then OpenID Connect, and enter a name.
- Copy the discovery URL, client id, and client secret it shows.
In your app
- Add the Ripplo provider to your better-auth config. baseUrl is the base URL the app already gives better-auth.ts
import { genericOAuth } from "better-auth/plugins/generic-oauth"; const RIPPLO_PROVIDER_ID = "ripplo"; function ripploProviderPlugins() { const clientId = process.env.RIPPLO_IDP_CLIENT_ID; const clientSecret = process.env.RIPPLO_IDP_CLIENT_SECRET; const discoveryUrl = process.env.RIPPLO_IDP_DISCOVERY_URL; if (clientId == null || clientSecret == null || discoveryUrl == null) { return []; } return [ genericOAuth({ config: [ { authentication: "basic", clientId, clientSecret, discoveryUrl, pkce: false, providerId: RIPPLO_PROVIDER_ID, redirectURI: `${baseUrl}/api/auth/oauth2/callback/${RIPPLO_PROVIDER_ID}`, scopes: ["openid", "email", "profile", "ripplo"], }, ], }), ]; } export const auth = betterAuth({ account: { accountLinking: { enabled: true, trustedProviders: [RIPPLO_PROVIDER_ID] } }, plugins: [...existingPlugins, ...ripploProviderPlugins()], }); - Add a GET route at your sign-in page address. The example uses Express. /dashboard is where a signed-in user lands.ts
import { fromNodeHeaders } from "better-auth/node"; app.get("/api/test-sso", (request, response) => { void auth.api .signInWithOAuth2({ body: { callbackURL: "/dashboard", providerId: "ripplo" }, headers: fromNodeHeaders(request.headers), returnHeaders: true, }) .then(({ headers, response: started }) => { headers.getSetCookie().forEach((cookie) => response.append("set-cookie", cookie)); response.redirect(302, started.url); }); }); - Set RIPPLO_IDP_CLIENT_ID, RIPPLO_IDP_CLIENT_SECRET, and RIPPLO_IDP_DISCOVERY_URL to the values from step 2 where your app runs, then deploy.
Back in Ripplo
- Go back to setup, or to the connection in the project's settings.
- Enter your app's address followed by /api/auth/oauth2/callback/ripplo as the callback, for example https://app.example.com/api/auth/oauth2/callback/ripplo. Settings calls this field Redirect URIs.
- Enter the path of that GET route as the Sign-in page, for example /api/test-sso.
next-auth and Auth.js
In Ripplo
- Run npx ripplo setup, or open the project's settings, choose Environment, then Sign-in connections, then Add connection, then OpenID Connect, and enter a name.
- Copy the discovery URL, client id, and client secret it shows.
In your app
- Add the Ripplo provider to your Auth.js config. allowDangerousEmailAccountLinking lets the email in the token create the user on first sign-in.ts
import NextAuth from "next-auth"; const ripploProvider = process.env.RIPPLO_IDP_CLIENT_ID != null && process.env.RIPPLO_IDP_CLIENT_SECRET != null && process.env.RIPPLO_IDP_DISCOVERY_URL != null ? [ { id: "ripplo", name: "Ripplo", type: "oidc" as const, clientId: process.env.RIPPLO_IDP_CLIENT_ID, clientSecret: process.env.RIPPLO_IDP_CLIENT_SECRET, wellKnown: process.env.RIPPLO_IDP_DISCOVERY_URL, authorization: { params: { scope: "openid email profile ripplo" } }, checks: ["state" as const], client: { token_endpoint_auth_method: "client_secret_basic" as const }, allowDangerousEmailAccountLinking: true, }, ] : []; export const { handlers, auth, signIn } = NextAuth({ providers: [...existingProviders, ...ripploProvider], }); - Add a route handler at your sign-in page address. /dashboard is where a signed-in user lands.ts
import { signIn } from "@/auth"; export async function GET(): Promise<Response> { if (process.env.RIPPLO_IDP_CLIENT_ID == null) { return new Response("Not found", { status: 404 }); } return signIn("ripplo", { redirectTo: "/dashboard" }); } - Set RIPPLO_IDP_CLIENT_ID, RIPPLO_IDP_CLIENT_SECRET, and RIPPLO_IDP_DISCOVERY_URL to the values from step 2 where your app runs, then deploy.
Back in Ripplo
- Go back to setup, or to the connection in the project's settings.
- Enter your app's address followed by /api/auth/callback/ripplo as the callback, for example https://app.example.com/api/auth/callback/ripplo. Settings calls this field Redirect URIs.
- Enter the path of that route handler as the Sign-in page.
Clerk
In Ripplo
- Run npx ripplo setup, or open the project's settings, choose Environment, then Sign-in connections, then Add connection, then OpenID Connect, and enter a name.
- Copy the discovery URL, client id, and client secret it shows.
In the Clerk dashboard
- Open SSO connections, choose Add connection, then For all users, then Custom provider.
- Set Name to "Ripplo" and Key to "ripplo". Clerk puts this information in the HTML of the auth screen, which Ripplo uses to sign in test users.
- Paste the discovery URL, client id, and client secret from step 2 into Discovery Endpoint, Client ID, and Client Secret.
- Select Add connection to save. Clerk then opens the connection page.
- Turn on Enable connection.
- If Bot sign-up protection is on, turn it off. Its challenge can stop the test browser.
- Copy the Authorized redirect URLs value Clerk shows, such as https://clerk.example.com/v1/oauth_callback.
Back in Ripplo
- Go back to setup, or to the connection in the project's settings.
- Paste that URL as the callback. Settings calls this field Redirect URIs.
- Enter the path of your login page as the Sign-in page, for example /login.
Ripplo opens that page and clicks the Ripplo button, so the page must show only one Ripplo button. After sign-in, the app must go to another path. A root path that shows the login form when signed out and the app when signed in does not work.
Keycloak
In Ripplo
- Run npx ripplo setup, or open the project's settings, choose Environment, then Sign-in connections, then Add connection, then OpenID Connect, and enter a name.
- Copy the discovery URL, client id, and client secret it shows.
In the Keycloak admin console
- In the realm your test app uses, open Identity providers and add an OpenID Connect v1.0 provider.
- Set Alias to "ripplo".
- Turn on Use discovery endpoint and paste the discovery URL from step 2 as the Discovery endpoint.
- Set Client authentication to Client secret sent as basic auth, then paste the client id and client secret from step 2 into Client ID and Client Secret.
- Set Scopes to "openid email profile ripplo".
- Turn on Trust Email and Hide on login page.
- Keep the default First login flow override, so Keycloak creates the user on first sign-in.
- Copy the Redirect URI Keycloak shows. It ends in /broker/ripplo/endpoint.
Back in Ripplo
- Go back to setup, or to the connection in the project's settings.
- Paste the Redirect URI as the callback. Settings calls this field Redirect URIs.
- Enter your login path with the provider hint as the Sign-in page, for example /login?kc_idp_hint=ripplo.
Any other library takes the same values through its generic OpenID Connect provider. Apps without single sign-on can use the Ripplo authentication adapter from the project's environment settings instead.
Test authentication
Once your app is deployed with the three values, Ripplo opens a tab on your sign-in page. If the page shows a Ripplo button, click it, as a review run does. Your app then signs in as a test user.
Continue in setup. If you stopped setup, run this command to start from this step.
npx ripplo setup --checkWhen sign-in works, setup installs the Ripplo plugin for Claude Code, if you use Claude Code, so it can read a review's findings and fix them.
Create your first tests
In Ripplo, open Reviews, choose New review, then Coverage. Ripplo explores your app and writes tests for its workflows. Pull request reviews run these tests, so create them before your first pull request review.
Review a pull request
Comment on a pull request into your default branch. Ripplo replies with a link to the review.
@ripplo reviewIf your host deploys each pull request to its own URL (Railway, Vercel, Netlify, Render, Cloudflare Pages, or PullPreview), Ripplo finds that URL in the deploy comment. Otherwise, deploy the branch and add its URL after @ripplo review.
To sign in through a connection other than the project default, add auth=<connection name> at the end. To review every pull request when its preview is ready, turn on Review every push in the project's environment settings.