---
title: Account sharing on web
description: Move the v2 web account-sharing integration onto v3. Swap the package, create a client, and replace Rupt.attach with rupt.evaluate.access from the same call site.
---

# Account sharing on web

Account sharing maps to the access event. In v2 you called `Rupt.attach`; in v3 you call `rupt.evaluate.access` from the same place, once per protected page view, for paying users. The call site does not move. What changes is the package, the way you create the client, and the shape of the call.

## Step 1: Swap the package

```sh
# remove the v2 package
npm uninstall rupt

# add the v3 client
npm install @ruptjs/client
```

Then update the import:

```js
// v2
import Rupt from "rupt";

// v3
import Rupt from "@ruptjs/client";
```

## Step 2: Create a client, then evaluate

v2 was a single global call. v3 creates a client once (this is where the logout callback lives) and calls `evaluate.access` at the same spot `attach` used to run.

```js
// v2
import Rupt from "rupt";

await Rupt.attach({
  client_id: "your_client_id",
  account: user.id,
  redirect_urls: {
    logout_url: "https://yourapp.com/logout",
    new_account_url: "https://yourapp.com/signup",
  },
  on_current_device_logout: () => {
    // Clear your session and sign the user out locally.
  },
  on_limit_exceeded: () => {},
  on_challenge: () => true,
});
```

```js
// v3
import Rupt from "@ruptjs/client";

const rupt = new Rupt({
  clientId: "your_client_id",
  on_logout: () => {
    // Clear your session and sign the user out locally.
  },
});

// Same call site as attach: once per protected page, for paying users.
await rupt.evaluate.access({
  user: user.id,
  email: user.email,
  phone: user.phone,
});
```

When Rupt detects sharing, the SDK redirects to the challenge on its own and brings the user back. You do not read the response for this. If you would rather intercept the challenge instead of auto-redirecting, pass `auto_challenge: false` and read `response.redirect` yourself.

## Step 3: Recreate your policies

v2 shipped with default account-sharing behavior. In v3 that behavior is explicit: it lives in policies you create in your [policies dashboard](https://app.rupt.dev/policies), on the access event. Recreate the three [checks](/docs/v3/concepts/checks) v2 came with, each triggering an account-sharing challenge:

- **Device limits** (`device_count`): more devices than one person uses.
- **Impossible travel** (`impossible_travel`): back-to-back activity from locations too far apart to bridge.
- **Concurrency** (`concurrent_sessions`): the account is live in two places at once.

Start from these three, then tune to your preference. Until a policy exists on the access event, `evaluate.access` just gathers signals and never challenges anyone.

## Step 4: Set the challenge URLs

In v2, `redirect_urls` lived in the `attach` call. In v3 they live on the policy's challenge config:

- **Success URL**: where a blocked user goes to create their own account. Point it at your signup page. Someone who hits a sharing challenge is high intent, so this converts the extra user instead of turning them away.
- **Logout URL**: where a device is redirected when it gets logged out. On the challenge screen, when the user chooses to log out the current device, that's where it lands.

The Logout URL is not the same as the `on_logout` callback, and account sharing uses both:

- **Logout URL** is a redirect, for the device the user is logging out from on the challenge page.
- **`on_logout`** is a callback that fires when the current session is logged out remotely, that is, when the user logs this device out from somewhere else. Use it to clear your app's own session. If a Logout URL is set, the SDK navigates there too; if not, `on_logout` is your only hook.

## What went away

| v2 (`attach`)                                   | v3                                                                 |
| ----------------------------------------------- | ------------------------------------------------------------------ |
| `client_id`                                     | `clientId` on the constructor                                      |
| `account`                                       | `user`                                                             |
| `redirect_urls`                                 | Success and Logout URLs on the policy's challenge config           |
| `on_current_device_logout`                      | `on_logout` on the constructor (or per call)                       |
| `on_challenge`                                  | Removed. The challenge auto-redirects (`auto_challenge` defaults on for access) |
| `on_limit_exceeded`                             | Removed. Cap devices with a `device_count` policy                  |
| `limit_config`, `tolerance`, `cookie`, `secret` | Removed from the call. Limits and tolerance are policy-side        |
| `device_id`, `attached_devices`, `access` in the response | Not returned. You do not need them client-side              |

## Related

- [Access protection](/docs/v3/fundamentals/access-protection): the account-sharing fundamental in full.
- [Account sharing prevention](/docs/v3/guides/account-sharing-prevention): the policies to add.
- [Account sharing on iOS and Android](/docs/v3/migration/account-sharing-on-mobile): the mobile version of this migration.
