There are two halves to the install, and the order matters because they feed each other:
- 1.Register a GitHub App → gives you an App ID, a private key (.pem), and a webhook secret.
- 2.Deploy the AWS infrastructure (CDK) → gives you a public webhook URL.
You create the GitHub App first (leaving its webhook URL blank), deploy AWS to get the URL, inject the GitHub secrets into AWS, then paste the URL back into the GitHub App:
GitHub App (register) AWS (deploy via CDK)
───────────────────── ──────────────────────
App ID ──┐
private key (.pem) ──┼──► setup-secrets.sh ──► SSM Parameter Store
webhook secret ──┘
cdk deploy ──► ApiGatewayUrl ──┐
│
Webhook URL ◄───────────────────────────────────────────── ┘0 · Prerequisites
Install these on your local machine before starting:
| Tool | Why | Check |
|---|---|---|
| AWS account + AWS CLI | RenderPR deploys here; CLI must be authenticated | aws sts get-caller-identity |
| Node.js 20+ | Runs the AWS CDK | node --version |
| AWS CDK CLI | Provisions the infrastructure | npm i -g aws-cdk · cdk --version |
| Docker (running) | CDK builds the Fargate image locally | docker info |
| Python 3.12+ | Lambda + agent code (only for tests) | python3 --version |
| jq & openssl | Used by the setup scripts | jq --version · openssl version |
| OpenRouter API key | LLM that writes the reviews | openrouter.ai |
| GitHub account/org | Where you register & install the app | — |
Your AWS identity needs permission to create: CloudFormation stacks, IAM roles, VPC + security groups, ECS clusters/tasks, Lambda, API Gateway, S3, CloudFront, and SSM parameters. An admin role is simplest; a scoped role works if it covers all of the above.
Make sure your AWS CLI is pointed at the region you want to deploy to (everything lives in one region):
# set Access Key, Secret Key, and default region (e.g. eu-west-1)
$ aws configure
# confirm you're authenticated as the right account
$ aws sts get-caller-identity1 · Register the GitHub App
Go to one of these, depending on whether the app belongs to your personal account or an organization:
- Personal: GitHub → your avatar →
Settings→Developer settings→GitHub Apps→New GitHub App - Organization: GitHub →
Your organizations→ pick the org →Settings→Developer settings→GitHub Apps→New GitHub App
Direct link (personal): github.com/settings/apps/new
Fill in the “Register new GitHub App” form. Here is the full form with the values to use — leave anything not listed at its default:
Notes on the fields:
- Webhook secret— generate one and keep it; you'll feed it into AWS in step 3. A good way to make one is
openssl rand -hex 32. RenderPR's Lambda verifies every webhook'sX-Hub-Signature-256HMAC against this exact value, so it must match what you store in AWS. - Webhook URL— you don't have it yet (it comes from the AWS deploy). Leave it blank; you'll set the real one in step 4.
- Permissions / events— these are the minimum RenderPR's code uses. Contents read and write is required because
@renderpr applycommits proposed changes back to the PR branch. The Lambda only acts on Pull request and Issue comment events.
1a · Generate the private key
After clicking Create GitHub App, you land on the app's settings page. Scroll to the Private keys section:
Generate a private key to sign access token requests.
Generate a private keyClick Generate a private key. A .pem file downloads automatically (e.g. renderpr-yourname.2026-06-16.private-key.pem). Save it somewhere safe — you give its path to the setup script in step 3. GitHub never shows it again.
1b · Note the App ID
At the top of the same page (the About section):
Write down the App ID— you'll enter it in step 3.
1c · Install the app on your repositories
In the left sidebar of the app's settings, click Install App, then click Install next to your account/org:
Install on:
Pick Only select repositories and choose the frontend repo(s) you want reviewed (you can add more later). Click Install.
github.com/settings/installations/<INSTALLATION_ID>. That trailing number is the installation ID — you only need it later if you want to store per-repo env vars / auth secrets (see the optional section below).At this point GitHub will start sending webhooks, but they'll fail until the AWS endpoint exists. That's expected — let's deploy it now.
2 · Deploy the AWS infrastructure
Clone the repo and install the CDK dependencies:
$ git clone https://github.com/pelazas/renderpr.git
$ cd renderpr/cdk
$ npm install2a · Bootstrap CDK (one-time per account + region)
$ npx cdk bootstrapThis creates the CDK's own support stack (an S3 bucket and IAM roles it uses to deploy). You only do this once per AWS account/region.
2b · Create the CloudFront signing key (required before first deploy)
Screenshots can contain private/authenticated UI, so RenderPR keeps the S3 bucket fully private and serves screenshots through CloudFront using signed URLs. The deploy will fail fastif this key doesn't exist yet, so run this first, from the repo root:
$ cd .. # back to the repo root
$ ./scripts/setup-cloudfront-key.shThis generates an RSA-2048 key pair, stores the private key in SSM (/renderpr/cloudfront-private-key, encrypted), and writes the public key to cdk/cloudfront-public-key.pem (gitignored). CDK reads that public key at deploy time.
2c · (Optional) tune cost / behavior knobs
The deploy works with zero configuration. If you want to change defaults, edit the context block in cdk/cdk.json or pass -c key=value flags to cdk deploy. The knobs the stack actually reads:
| Context key | Default | What it does |
|---|---|---|
| maxConcurrentTasks | 5 | Hard cap on simultaneous review containers (cost guard) |
| maxTaskAgeSeconds | 1500 | Reaper force-stops tasks older than this |
| reaperIntervalMinutes | 5 | How often the cleanup Lambda runs |
| webhookRateLimit / Burst | 20 / 40 | API Gateway throttling |
| idleTimeoutSeconds | 900 | Idle time (15 min) before a task self-terminates |
| pollIntervalSeconds | 10 | Seconds between PR-comment polls |
commandToken, openrouterApiKey, or repositoryAllowlist in cdk.json — older docs mention these but the current stack does not read them. The command token is generated automatically by the secrets script (step 3), and the OpenRouter key is prompted there too.2d · Deploy
$ cd cdk
$ npx cdk deployThe first deploy takes several minutes (it builds the Docker image, creates a VPC, ECS cluster, Lambda functions, API Gateway, S3, and a CloudFront distribution). Approve the IAM/security-group changes when prompted.
When it finishes, CDK prints an Outputs block. Copy the ApiGatewayUrl— that's your webhook URL:
Outputs:
RenderprStack.ApiGatewayUrl = https://abc123xyz.execute-api.eu-west-1.amazonaws.com/
RenderprStack.ClusterArn = arn:aws:ecs:eu-west-1:...:cluster/renderpr-cluster
RenderprStack.GitHubParamName = /renderpr/github-app
RenderprStack.ScreenshotBucketName = renderpr-screenshots-<account-id>
RenderprStack.ScreenshotDistributionDomain = dxxxx.cloudfront.net
RenderprStack.TaskDefinitionArn = arn:aws:ecs:...:task-definition/renderpr-review:N3 · Inject the GitHub + OpenRouter secrets into SSM
From the repo root, run:
$ bash scripts/setup-secrets.shIt prompts for four things you collected in step 1 (plus your OpenRouter key):
=== RenderPR — Post-Deploy Secret Injection === GitHub App ID: 123456 Path to GitHub App private key (.pem file): ~/Downloads/renderpr-yourname.2026-06-16.private-key.pem Webhook Secret: ******** (the value from step 1) OpenRouter API Key: ******** (sk-or-v1-...)
This writes:
/renderpr/github-app— JSON{app_id, private_key, webhook_secret}(encrypted)/renderpr/openrouter— your OpenRouter key (encrypted)/renderpr/renderpr-command-token— a fresh random token it generates for you, if one doesn't already exist (this is the Lambda ↔ container auth for@renderprconversational commands)
The Fargate task role has read-only access to these.
cdk deploy to roll the Lambda.4 · Point the GitHub App at your webhook URL
Back in the GitHub App settings (Developer settings → GitHub Apps → your app → General), find the Webhook section and set the URL to the ApiGatewayUrl from step 2d:
Click Save changes. GitHub immediately sends a ping to test it.
You can check delivery health under the app's Advanced tab → Recent Deliveries, where each webhook shows a green ✓ (2xx) or red ✗ with the response body — handy for debugging.
5 · Verify the installation
- 1.Open a pull request that touches the frontend in one of your installed repos (or comment
@renderpr review thison an existing PR). - 2.Within a few seconds you should see a live progress comment from the app: a checklist that updates through setup → install → dev server → screenshots → review.
- 3.It edits that same comment into the final review — screenshots at 4 viewports plus an LLM analysis of the diff.
- 4.The review includes a live preview link (
http://<public-ip>:3000) to the running app. It works only while the task is alive (15-minute idle window).
Try the conversational commands while the task is still running:
@renderpr code change: make the header sticky— the LLM edits the cloned repo, re-runs the dev server, and posts updated screenshots.@renderpr apply— commits the proposed change to the PR branch.
6 · (Optional) Per-repo env vars & auth-gated apps
If your app needs environment variables to build, or hides pages behind a login, store per-repo secrets in SSM and add a .renderpr.yml to the repo.
Store secrets (you need the installation ID from step 1c):
$ scripts/renderpr-secrets.sh <installation_id> <owner/repo> \
NEXT_PUBLIC_API_URL=https://api.example.com \
NEXTAUTH_SECRET="$(openssl rand -hex 32)"They're stored at /renderpr/secrets/{installation_id}/{owner}/{repo}/{KEY}, and each review task can only read its ownrepo's path.
Then commit a .renderpr.yml to the repo root:
.renderpr.yml
env:
from: .env.example # which vars to inject from your stored secrets
auth:
type: jwt # nextauth | jwt | supabase | clerk | firebase
user:
email: preview@example.com
name: Preview User
role: admindocs/AUTH_AND_ENV.md.7 · Updating and tearing down
Update (after pulling new code or changing config)
$cd cdk && npx cdk deployCDK diffs and updates only what changed. SSM secrets are preserved. There's also a GitHub Actions workflow (.github/workflows/deploy.yml) that redeploys automatically when src/**, cdk/**, or the Dockerfile change.
Tear down (removes all AWS resources this stack created)
$cd cdk && npx cdk destroySSM parameters are not deleted by destroy (they persist in your account); the CloudFront key, GitHub credentials, and OpenRouter key stay unless you remove them manually with aws ssm delete-parameter.
Troubleshooting
Webhook deliveries show ✗ with 401/403▾
setup-secrets.sh, then cdk deploy to roll the Lambda.cdk deploy errors: “CloudFront signing public key not found”▾
./scripts/setup-cloudfront-key.sh, then deploy again.No progress comment appears▾
WebhookHandler Lambda. Confirm the app is installed on that repo and Pull request / Issue comment events are subscribed.Fargate task starts then dies▾
.pem formatting, or the cloned project's npm ci / npm run dev fails.No review comment, task ran▾
/renderpr/openrouter and the private key in /renderpr/github-app.Live preview link dead▾
npm ci fails on native modules▾
apt-get install line in the Dockerfile and re-deploy.docs/ARCHITECTURE.md, docs/DEPLOYMENT.md, and docs/WORKFLOW.md.That's the whole install.
Star the repo to follow along, or grab the source and deploy it into your own AWS in a few minutes.