integrations:posthog:connect creates an org and project before any confirmation, with no way to use an existing PostHog project
- Dominant language
- TypeScript
- Stars
- 1.4k
- Forks
- 236
- Avg merge
- 3d 8h
- Merged PRs (30d)
- 98
Description
### Summary
Two related gaps in `eas integrations:posthog:connect`:
1. It creates a PostHog organization and project **before any confirmation**. The only prompt beforehand is region selection.
2. There is no way to point the connection at a **pre-existing** PostHog project.
Together these mean a developer who already uses PostHog, and whose PostHog account email differs from their Expo account email, gets a brand-new PostHog account, organization, and project created for them — with no opportunity to say "use the project I already have," and no chance to decline before the resources exist.
To be clear about scope: the command **does** prompt before overwriting `EXPO_PUBLIC_POSTHOG_*` in `.env.local` and in EAS, so existing configuration is not silently replaced. The problem is confined to the provisioning step, which happens earlier and unconditionally.
### Why it happens
In `build/commands/integrations/posthog/connect.js` (eas-cli 22.3.0), the project mutation accepts no project selector:
```js
project = await PostHogMutation.setupPostHogProjectAsync(graphqlClient, {
appId: projectId,
posthogOrganizationConnectionId: connection.id,
})
```
and the lookup only finds a project EAS previously created for that app:
```js
let project = await PostHogQuery.getPostHogProjectByAppIdAsync(graphqlClient, projectId)
```
There is an org-level reuse path, but it is gated on email identity:
```js
throw new Error(`The email on the ${account.name} account already has a PostHog account,
which must be connected by approving it in a browser. ...`)
```
If the Expo account's email has no PostHog account, the server takes the create branch. So a developer whose PostHog login differs from their Expo login always gets new resources. Even the browser-approval branch reuses only the **organization** — the project is still newly created.
### Managed or bare?
Bare — native directories are committed. Not relevant to the failure; the command never reaches native code.
### Environment
- eas-cli 22.3.0, darwin-arm64, node 22.22.0
- Expo SDK 54, pnpm workspace monorepo
- PostHog EU Cloud
### Reproducible steps to reproduce from a blank project
1. Create a PostHog project manually and note that its account email differs from your Expo account email.
2. Run `eas integrations:posthog:connect` and select a region.
Observed:
```
✔ Select a PostHog region › European Union (EU)
✔ Created PostHog organization -XXXXXXXX
✔ Created PostHog project
? PostHog features to set up ›
```
The organization and project already exist by the time the first feature prompt appears. Aborting here (Ctrl-C) leaves them behind.
### Expected behavior
Either of these would resolve it:
1. **Confirm before provisioning.** e.g. `No PostHog account found for . Create a new organization and project? (y/N)`. This matters more than a typical confirmation because the CLI cannot undo it: `eas integrations:posthog:disconnect` removes only the EAS-side link record, and the created organization must then be deleted in the PostHog UI — under an account auto-created for the Expo account's email, which the developer may not realize exists or have credentials for.
2. **Allow using an existing project.** A prompt to select from the connected organization's projects, and/or `--posthog-project-id` / `--posthog-organization-id` flags for the non-interactive case.
### Note on the docs
https://docs.expo.dev/guides/using-posthog/ says *"Re-running `connect` is safe: it reuses your existing organization and project."* In context this means "what EAS previously created," but it reads naturally as "it will find the PostHog project I already have" — which is what led me to run the command expecting a link rather than a provision.
Contributor guide
Research direction
Start in build/commands/integrations/posthog/connect.js, then inspect PostHogMutation.setupPostHogProjectAsync and PostHogQuery.getPostHogProjectByAppIdAsync. Trace when provisioning occurs relative to the region and feature prompts. Done means the command confirms before creating resources and provides a documented path to select or specify an existing PostHog project.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- api, cli
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100