<pectus.ai/>
./pectus.ai — builder framework · self-hosted · MIT

For end users

Set up your accounts

Pectus needs three accounts before the install agent can do its work: Anthropic for Claude, Supabase for the database, and a Google service account for analytics data. Set them up before you start the install — the agent expects every key, URL, and JSON file to already be in hand when it asks.

Plan for 30 to 40 minutes total. Most of the time goes into clicking through signup screens. The free tiers cover Pectus comfortably; the only thing you spend money on is Anthropic API credits, with a $5 minimum to load.

Jump to: Anthropic · Supabase · Google service account

Anthropic

Pectus uses Claude (Anthropic’s model) for every analysis, draft, and brand-aware skill. You need an API account separate from any Claude.ai chat subscription. The free Claude.ai plan and the $20/month Pro plan are chat products. Neither one gives you API access.

Plan for 5 minutes. Cost: $5 minimum to load credits.

Step 1. Create the account

  1. Open https://console.anthropic.com.
  2. Click Sign Up. Sign up with email or “Continue with Google”.
  3. Verify your email if prompted. Open the verification email and click the link.
  4. You land on the Anthropic Console dashboard.

Step 2. Add a payment method and load credits

The Anthropic API is pay-as-you-go: you load credits, then API calls draw down from the balance. There’s no monthly subscription.

  1. In the left sidebar, click Plans & Billing.
  2. Click Add Payment Method. Enter card details. Save.
  3. Click Buy Credits (or Add to Balance). Pick an amount; $5 is the minimum and is enough for several weeks of Pectus use for a single brand running weekly analyses.
  4. Confirm. The balance updates immediately.

A typical Pectus user spends $0.50 to $5 per week on API credits, dominated by weekly analysis runs and the page builder. The dashboard’s “Refresh insights” button is gated behind a cost-warning so you don’t accidentally rack up charges.

Step 3. Create an API key

  1. In the left sidebar, click API keys.
  2. Click Create Key.
  3. Name the key something memorable, e.g. pectus.
  4. Copy the key. It starts with sk-ant- and is only shown once. Paste it into your password manager right now. If you lose it, you’ll have to delete and recreate.
  5. Click Done.

Step 4. Hand the key to Pectus

When the install agent asks for ANTHROPIC_API_KEY, paste the value you just copied. Pectus writes it to ~/pectus/.env.local. The file is gitignored; nothing leaves your machine.

If you ever need to rotate the key (compromised, accidentally shared), come back to API keys in the Anthropic Console, click Delete on the old key, and create a new one. Update .env.local and restart npm run dev.

What if I already have a Claude.ai chat subscription?

The chat product and the API are billed separately at Anthropic. Your $20/mo Claude Pro subscription does not give you API access and does not subsidize API calls. You still need to load API credits to use Pectus.

The two are deliberately separate billing rails. The Claude.ai web/desktop product is for humans chatting with Claude; the API is for software talking to Claude. Pectus is software, so it goes through the API rail.

What if my key stops working?

Three causes, in order of likelihood:

  1. You ran out of credits. Open the Anthropic Console, check Plans & BillingBalance. If it shows $0, top up.
  2. The key was rotated. If someone else in your organization rotated keys without telling you, your old sk-ant-... value will return 401. Check API keys for the current valid key.
  3. You hit a rate limit. Free tier Anthropic accounts have low per-minute limits. If you’re running many things in parallel, you may briefly 429. Wait a minute and retry; or move to a higher tier.

If none of those: paste the exact error your install agent shows, plus the first 8 characters of your key (e.g. sk-ant-a — never share more), at https://github.com/pectusai/pectus/issues.

Supabase

Supabase is the database Pectus stores everything in: brand profile, workspaces, ICP, keywords, articles, page drafts, skill runs, the review queue. You create the project; Pectus only consumes the credentials.

Plan for 10 minutes. Cost: free tier is enough for one brand with comfortable headroom (500MB database, 1GB storage, 2GB bandwidth per month).

Step 1. Create the account

  1. Open https://supabase.com.
  2. Click Start your project (top right).
  3. Sign up with GitHub (easiest) or email. If GitHub, approve the OAuth scopes.
  4. Verify your email if prompted.

You land on the Supabase dashboard with an empty Organizations list.

Step 2. Create an organization

The first time you sign in, Supabase asks you to create an organization. An organization is a billing container; one organization can hold many projects.

  1. Pick a name, e.g. your full name or your brand name.
  2. Pick Free as the pricing tier. You can upgrade later if you outgrow the limits.
  3. Click Create organization.

Step 3. Create the project

  1. Click New Project.
  2. Pick the organization you just created.
  3. Fill in:
    • Name: a memorable name, e.g. pectus-acme or just pectus. Lowercase, dashes, no spaces.
    • Database Password: click Generate a password to get a strong one. Copy this immediately and save in your password manager. You’ll need it later if you ever connect to the database directly. Pectus itself doesn’t use this password (it uses API keys instead), but it’s not recoverable if you lose it.
    • Region: pick the one closest to where you and most of your users live. Latency is regional.
    • Pricing Plan: Free. (You can upgrade to Pro later for $25/month if you outgrow the free tier limits.)
  4. Click Create new project.
  5. Wait 1 to 2 minutes. Supabase provisions a Postgres database, sets up authentication, and creates the storage buckets. The page shows progress.

Step 4. Grab the three values Pectus needs

Once the project is provisioned, you land on the project dashboard. Pectus needs three values from this project. All three live in the same place.

  1. In the left sidebar, click the gear icon (Project Settings) at the bottom.

  2. Click API in the settings sidebar.

  3. You’ll see three things you need:

    • Project URL — labeled “Project URL”. Looks like https://xxxxxxxxxxxxxxx.supabase.co. Copy it.
      • Pectus calls this NEXT_PUBLIC_SUPABASE_URL.
    • anon / public key — under “Project API keys”, the row labeled anon public. A long JWT-shaped string. Copy it.
      • Pectus calls this NEXT_PUBLIC_SUPABASE_ANON_KEY.
      • This key is safe to ship to browsers; it relies on Row Level Security to scope access. Do not worry that it’s labeled “public”.
    • service_role key — under “Project API keys”, the row labeled service_role secret. Click the eye icon to reveal, then copy.
      • Pectus calls this SUPABASE_SERVICE_ROLE_KEY.
      • Treat this like a database root password. It bypasses Row Level Security. Never ship to browsers, never paste into a chat, never commit to git.

Save all three to your password manager. The install agent will ask for them when it gets to the database setup step.

Step 5. Create your admin user

After the install agent runs the migration SQL, you need to create the admin login that Pectus’s CMS will use.

  1. In the Supabase project sidebar, click Authentication.
  2. Click Users in the sub-sidebar.
  3. Click Add userCreate new user.
  4. Fill in:
    • Email: any email you want to log into the CMS with. Personal Gmail is fine.
    • Password: pick a strong password. Save in your password manager. Pectus does not store this password; only Supabase does (one-way hashed).
    • Auto Confirm User: tick this so you don’t have to deal with a verification email.
  5. Click Create user.

This is the email and password you’ll use to sign into http://localhost:3000 once Pectus is running.

Common pitfalls

The service_role key looks the same as the anon key. They’re both long JWT strings. The label tells them apart. Mixing them up means the CMS either can’t read user data (anon where service_role expected) or has root access where it should be scoped (service_role where anon expected). Read the label carefully.

You created the project but the Project URL field is empty. Provisioning takes 1 to 2 minutes. Refresh the Settings → API page after the green “ready” indicator appears in the project header.

You’re getting “Invalid API key” errors after pasting into .env.local. Two causes: a trailing newline got pasted in, or you pasted the wrong key. Open .env.local in a text editor; each KEY=value line should fit on one line with no quotes around the value. If unsure, recopy from Supabase.

You forgot the database password. It’s only needed for direct database access (rare). For Pectus you don’t need it; the API keys do everything Pectus needs. If you need to reset it, Supabase Project Settings → Database → Reset database password.

Storage and limits

The free tier covers one brand with comfortable headroom. Specifically: 500MB database, 1GB storage (for uploaded brand assets and reference images), 2GB egress bandwidth per month, 50,000 monthly active users.

When you outgrow these, Supabase shows in-dashboard banners. The Pro plan is $25/month per project and lifts limits roughly 10x. You don’t need to think about this for the first many months.

Google service account

Pectus reads from Google Analytics 4 and Google Search Console using a single service account. A service account is a non-human Google identity that can be granted access to the same properties a human can. Pectus uses one service account to talk to all three Google APIs (GA4, Search Console, Google Ads).

Plan for 15 to 20 minutes. Most of the time goes into clicking through Google Cloud Console screens. Cost: free at Pectus-scale usage.

Step 1. Sign in with the right Google account

This is the trap most people fall into. The Google account you sign into Cloud Console with must be the same Google account that owns the GA4 property and Search Console site you want Pectus to read. If they’re different accounts (e.g. you sign in to GA4 with you@yourbrand.com and to Cloud with you@gmail.com), the service account you create will be invisible to GA4.

Quick check: open https://analytics.google.com/ and look at the avatar in the top right. Then open https://console.cloud.google.com/ and look at its top-right avatar. They should be the same email.

If they’re not, sign out of Cloud Console and sign back in with the GA4-owning account before continuing.

Step 2. Create a Google Cloud project

  1. Open https://console.cloud.google.com.
  2. In the top bar, click the project dropdown (it might say “Select a project” or show an existing project name).
  3. Click New Project (top-right of the dropdown panel).
  4. Fill in:
    • Project name: any descriptive name, e.g. acme-corp or acme-pectus.
    • Organization: leave as “No organization” if you don’t have a Google Workspace org. Otherwise pick yours.
    • Location: leave default.
  5. Click Create.
  6. Wait 10 to 30 seconds. The top-right shows a notification when the project is ready.
  7. Click the project dropdown again and select your new project. Confirm the top bar now shows the new project name.

Note the project ID. Google generates it from the project name with a numeric suffix (e.g. acme-corp-NNNNNN). You can’t change it; it shows up in service account email addresses later.

Step 3. Enable three APIs

The service account is just an identity. To talk to GA4 or Search Console, you need to enable the corresponding API in your project. Pectus needs three APIs enabled. Do not skip this step: missing the Google Analytics Admin API is the most common cause of the “this user doesn’t exist” error in GA4 later.

For each of the three:

  1. In Google Cloud Console, open the hamburger menu (top-left) → APIs & ServicesLibrary.
  2. Search for the API name (see list below).
  3. Click the API in the result list.
  4. Click Enable. Wait 5 to 30 seconds for the page to flip to “API enabled”.

The three APIs:

  • Google Analytics Admin API — lets the service account be recognized as a valid principal in GA4’s user management UI. This is the one that prevents “this user doesn’t exist” errors.
  • Google Analytics Data API — lets Pectus read the actual GA4 report data.
  • Google Search Console API — reads Search Console performance data.

(If you also want Google Ads later, enable Google Ads API here too. Optional.)

Step 4. Create the service account

  1. Hamburger menu → IAM & AdminService Accounts.
  2. Click + CREATE SERVICE ACCOUNT (top of page).
  3. Fill in:
    • Service account name: your-account (or any name; it’s a label).
    • Service account ID: Google fills this in from the name. Leave default.
    • Description: optional. “Reads GA4 and Search Console for Pectus” works.
  4. Click Create and Continue.
  5. Skip the “Grant this service account access to project” step. Pectus doesn’t need any project-level role; access is granted per-property in GA4 and Search Console (next steps). Click Continue.
  6. Skip the “Grant users access to this service account” step. Click Done.

You’re back on the Service Accounts list. Your new service account appears with an email like your-account@acme-corp-NNNNNN.iam.gserviceaccount.com. Click the email to open the service account.

Step 5. Download the JSON key

  1. On the service account detail page, click the Keys tab.
  2. Click Add KeyCreate new key.
  3. Pick JSON as the key type.
  4. Click Create.

Your browser downloads a JSON file with a name like acme-corp-NNNNNN-abc123def456.json. Save it somewhere safe.

Open the file in a text editor to verify it. You should see fields including:

  • "type": "service_account" — confirms this is the right kind of credential. If it’s "authorized_user", you downloaded the wrong thing; go back and redo step 4 as a service account, not an OAuth client.
  • "project_id"
  • "private_key_id"
  • "private_key" — a long PEM-formatted block. This is the secret half.
  • "client_email" — the service account’s email address. You’ll paste this into GA4 and Search Console next.

Treat this file like a password. Save it in your password manager (some managers let you attach files), or store it somewhere encrypted. Pectus consumes the JSON contents but doesn’t keep the file around; the install agent uploads or pastes it during the database step, after which it lives only in your Supabase integrations table.

Step 6. Add the service account to GA4

  1. Open https://analytics.google.com/ and sign in (same Google account as Cloud).
  2. Pick the GA4 property Pectus should read. (If you have multiple, the workspace will be tied to whichever you pick.)
  3. Click the Admin gear (bottom left).
  4. In the Property column, click Property access management.
  5. Click the blue + in the top-right → Add users.
  6. Email addresses: paste the client_email value from the JSON file. The email looks like your-account@acme-corp-NNNNNN.iam.gserviceaccount.com. Don’t type it; copy from the JSON to avoid typos in the project ID middle segment.
  7. Untick “Notify new users by email”. Service accounts have no inbox; the notify step can throw.
  8. Direct roles and data restrictions: tick Editor (or Viewer if you only need read access).
  9. Click Add.

If GA4 says “this user doesn’t exist”, three causes in order:

  • The Google Analytics Admin API isn’t enabled (step 3). Most common.
  • The email is mangled (you typed it instead of copying). Re-copy from the JSON.
  • You’re signed into the wrong Google account (step 1). Check the avatar in the top-right.

If the email is correct and the API is enabled but it still errors, wait 30 minutes and retry. Google’s identity systems can take that long to propagate a fresh service account.

If GA4’s “Add users” UI still rejects the email

There’s a known long-running bug where the GA4 add-user dialog refuses to validate *.iam.gserviceaccount.com emails for some users, even when everything else is correct. The error reads “Failed to add user: email not found” or “This email doesn’t match a Google Account” and a red triangle appears next to the email. Incognito mode does not fix it. Waiting days does not fix it. The dialog is just broken for that user/property combination.

The workaround: bypass the UI and add the service account using the Google Analytics Admin API directly. The API has none of the UI-side validation, so it accepts the same email the dialog rejects. Five minutes, no terminal required.

  1. Find your GA4 Property ID. In GA4: AdminProperty column → Property details. The Property ID is a number like 123456789 (not the G-XXXXXXX measurement ID, that’s different).
  2. Open the OAuth 2.0 Playground. Go to https://developers.google.com/oauthplayground/.
  3. Authorize the right scope. In the left panel under “Step 1 Select & authorize APIs”, scroll past the pre-listed APIs to the “Input your own scopes” field at the bottom. Paste exactly:
    https://www.googleapis.com/auth/analytics.manage.users
    Click Authorize APIs. Sign in with the same Google account that owns GA4 and the Cloud project. Click Allow.
  4. Exchange code for token. The playground lands you on Step 2. Click the blue Exchange authorization code for tokens button. An access token populates in the field below.
  5. Build the request. Scroll to Step 3.
    • HTTP Method: change from GET to POST.
    • Request URI: paste, replacing <PROPERTY_ID> with the number from step 1:
      https://analyticsadmin.googleapis.com/v1alpha/properties/<PROPERTY_ID>/accessBindings
      (The endpoint is in v1alpha, not v1beta. v1beta returns 404.)
    • Enter request body: click that field, then paste a single-line JSON with the service account email and the role you want (viewer, analyst, editor, or admin):
      {"user":"your-account@acme-corp-NNNNNN.iam.gserviceaccount.com","roles":["predefinedRoles/viewer"]}
      Make sure the quotes are straight ("), not curly. If you copy-pasted from a rich-text source the JSON parser will reject it silently.
    • Content-Type: should already be application/json.
  6. Send. Click Send the request. A 200 OK with a JSON body containing name, roles, and user means the service account is now bound to the property as Viewer. Refresh GA4’s Property access management page; the service account appears in the list.

If you get a 400 Bad Request, the request body is malformed (re-paste cleanly). If you get a 403 Forbidden, the signed-in Google account isn’t an Administrator on that GA4 property. If you get a 404 Not Found, you used v1beta instead of v1alpha.

Step 7. Add the service account to Search Console

  1. Open https://search.google.com/search-console/.
  2. Pick the property (site) Pectus should read. URL-prefix property and Domain property both work.
  3. Click Settings (gear icon, bottom-left).
  4. Click Users and permissions.
  5. Click Add user (top right).
  6. Email: paste the same client_email value from the JSON.
  7. Permission: pick Owner (full access) or Restricted (read-only). Restricted is enough for Pectus.
  8. Click Add.

Same propagation delay rule applies: if it errors immediately after creating the service account, wait 30 minutes.

If the API path is genuinely blocked for you (some Google Workspace organizations restrict it), the workaround is to use a Domain property instead. Domain properties verify via DNS TXT record; once verified, the service account doesn’t need to be added separately. See the GA4 / Search Console troubleshooting FAQ for that path.

Step 8. Hand the JSON to Pectus

When you reach the install agent’s “Connect Google” step, it asks for the service account JSON. Two ways to provide it:

  • From the CMS (after install): open /apps/ga4 (or /apps/gsc), use the file picker to upload the JSON, or paste the file contents into the textarea.
  • From the CLI during install: the npx pectus connect google command asks for the file path. Paste the absolute path to the downloaded JSON.

Pectus stores the JSON in your Supabase integrations table where it stays for every Google API call. One service account powers all three Google apps: GA4, Search Console, and Google Ads (when you activate it later).

Common pitfalls

  • Wrong Google account. Sign into Cloud Console with the same Google account that owns GA4 and Search Console. If they’re different, the service account is invisible from where you’re standing in GA4.
  • Forgot to enable the Admin API. This causes the most-reported error: “this user doesn’t exist” when adding the SA to GA4. Step 3 fixes it. After enabling, wait 30 seconds before retrying.
  • Typed the email instead of copying. The project ID middle segment includes characters that are easy to mistype. Always paste from the JSON file’s client_email field.
  • Notify by email is on. Service accounts have no inbox. GA4 may throw an internal error trying to notify them. Untick the notify checkbox.
  • You downloaded an OAuth client credential instead of a service account key. The JSON’s type field tells you which: service_account is what Pectus needs; authorized_user is the wrong kind. Go back to step 4.