Skip to content

feat(with-privy): add account linking and one-liner Privy identify - #129

Draft
yosriady wants to merge 1 commit into
mainfrom
claude/privy-account-linking
Draft

feat(with-privy): add account linking and one-liner Privy identify#129
yosriady wants to merge 1 commit into
mainfrom
claude/privy-account-linking

Conversation

@yosriady

@yosriady yosriady commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Demonstrates Privy account linking and how Formo clusters a multi-wallet Privy user into a single user.

Important

Draft — blocked on the SDK release. This example uses formo.identify(user, { privy: true }), added in getformo/sdk#304 and not yet published. package.json therefore requires @formo/analytics ^1.34.0, so CI's pnpm install --frozen-lockfile will fail until that version is on npm. Once it publishes: run pnpm install in with-privy/ to refresh the lockfile, then mark this ready for review.

The problem

A Privy user is one account (a DID) with many linked wallets. Formo's analytics is address-keyed, so one person with 8 wallets becomes 8 Formo users — retention, conversion, and user counts are all wrong.

What changed

src/components/LinkedAccounts.tsx (new) — the account-linking surface:

  • useLinkAccount with link buttons for 15 account types. Already-linked types are hidden, except wallets and passkeys, which Privy allows many of.
  • Per-account unlink routed to the matching Privy method. unlinkOAuth covers both built-in <provider>_oauth types and custom custom:<provider> ones. Types with no unlink method (custom_auth, guest) are disabled rather than left to throw, and unlink is disabled entirely when one account remains, since Privy requires a user to keep at least one.
  • A live parsePrivyProperties(user) preview showing exactly what identify() sends.

src/app/page.tsx — replaces the manual parsePrivyProperties loop with the one-liner:

formo.identify(user, { privy: true, activeAddress });

This identifies every linked wallet under the user's DID in one call. Only the active wallet takes over event attribution; the rest are recorded for clustering.

Two React details worth reviewing

  • The identify effect depends on the active address string, not the useWallets() array — that array is a new reference on many renders and would re-run the effect every render.
  • The link callbacks deliberately do not re-identify. user is reactive, so the effect already re-runs after every link/unlink; identifying from a callback can run against a pre-link user and emit a redundant, out-of-order identify just before the effect emits the correct one.

Verification

tsc --noEmit clean and next build succeeds against a local build of the SDK branch.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.

Review in cubic

Demonstrates Privy's account-linking flow and how Formo clusters a
multi-wallet Privy user into a single user.

- New LinkedAccounts component using useLinkAccount: link buttons for 15
  account types (hiding already-linked ones, except wallets and passkeys
  which Privy allows many of), per-account unlink routed to the matching
  Privy method, and a live parsePrivyProperties() preview of exactly what
  identify() sends.
- Unlink is routed by account type; unlinkOAuth handles both built-in
  <provider>_oauth types and custom "custom:<provider>" ones. Types with no
  unlink method (custom_auth, guest) are disabled rather than left to fail,
  and unlink is disabled entirely when only one account remains, since
  Privy requires a user to keep at least one.
- page.tsx replaces the manual parsePrivyProperties loop with
  formo.identify(user, { privy: true, activeAddress }), which identifies
  every linked wallet under the user's DID in one call.
- The identify effect depends on the active address string rather than the
  useWallets() array, which returns a new reference on many renders and
  would otherwise re-run the effect every render. It deliberately does not
  re-identify from the link callbacks: `user` is reactive, so the effect
  already re-runs, and identifying from a callback can run against a
  pre-link user and emit a redundant, out-of-order identify.

Requires @formo/analytics 1.34.0 for the identify(user, { privy: true })
form, which is not published yet — see the PR description.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@socket-security

Copy link
Copy Markdown

Dependency limit exceeded — report not shown.

This pull request scan exceeded the 10,000-dependency limit applied to this scan, so the results are incomplete and may be inaccurate. To avoid reporting false positives, Socket has not posted a report.

Upgrade your plan to raise the dependency limit and get complete reports, or view the partial scan in the dashboard.

Socket is always free for open source. If this is a non-commercial open source project, contact us to request a free Team account.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant