---
updatedAt: 2026-09-25T18:25:26.000Z
agentTools:
  projectIndex: https://docs.atono.io/llms.txt
---

# Feature engagement

Track feature usage in your application using the Atono SDK.

The Atono SDK lets you track how users interact with a feature by recording usage events and sending them to Atono. Each usage event is associated with a specific story, so you can see how the feature behind that story is being adopted.

Usage data appears in the [Feature engagement](https://docs.atono.io/docs/feature-engagement) graph on the story and across all tracked features on the [Engagement](https://docs.atono.io/docs/top-features) page.

The Web and React SDKs require version 1.1.0 or later for usage tracking. For installation and initialization instructions, see [Get started with the Atono SDK](https://docs.atono.io/docs/get-started-with-the-atono-sdk).

<br />

***

# Record usage

Call `record()` when someone interacts with the feature you want to track. The usage key is the story ID from Atono, such as `STORY-67`. You can copy the story ID from the story header.

Each time `record()` is called, the SDK records a timestamped usage event associated with the current environment and, when available, the customer and location. The story’s Feature engagement graph updates automatically.

## Web

In this example, `button` represents a reference to a specific element in the application:

```javascript
const usage = atono.getUsageReporter();

button.addEventListener('click', () => {
    usage.record('STORY-67');
});
```

Replace `STORY-67` with the ID of the story associated with the feature.

## React

Use the `useUsageReporter()` hook in a component inside `<AtonoProvider>`:

```jsx React
import { useUsageReporter } from '@atono-io/react-sdk';

function TryButton() {
    const { record } = useUsageReporter();

    return (
        <button onClick={() => record('STORY-67')}>
            Try the feature
        </button>
    );
}
```

Replace `STORY-67` with the ID of the story associated with the feature.

## Java

Call `record()` on the usage reporter when someone uses the feature you want to track. The usage key identifies the story associated with the feature, such as `STORY-67`.

```java Java
atono.getUsageReporter().record("STORY-67");
```

Replace `STORY-67` with the ID of the story associated with the feature.

Usage events are published asynchronously, so calling `record()` doesn’t block while the SDK communicates with Atono.

## Node.js

Call `record()` on the usage reporter when someone uses the feature you want to track. Pass the ID of the story associated with the feature, such as `STORY-67`.

```javascript Javascript
atono.getUsageReporter().record('STORY-67');
```

Replace `STORY-67` with the ID of the story associated with the feature.

Usage events are published asynchronously, so calling `record()` doesn’t block while the SDK communicates with Atono.

***

# Provide customer and location context

Context lets Atono associate usage with a particular customer or location.

Customer context is optional. If an event doesn’t include a customer value, its usage appears as **Unknown** in the Feature engagement graph.

How you provide context depends on the SDK.

## Web

The Web SDK detects location automatically from the user’s IP address.

Set customer context after initializing the SDK:

```javascript JavaScript
await atono.setContext({
    customer: 'your-customer-id'
});
```

Replace `your-customer-id` with the customer identifier used in your application.

Set the environment key once per session. If the active customer changes, update the context before calling `record()` so the event includes the latest value.

## React

The React SDK detects location automatically from the user’s IP address.

Provide customer context through `<AtonoProvider>`:

```jsx React
import { AtonoProvider } from '@atono-io/react-sdk';

function RootComponent() {
    const evaluationContext = {
        customer: 'your-customer-id'
    };

    return (
        <AtonoProvider
            environmentKey="<your-environment-key>"
            evaluationContext={evaluationContext}
        >
            <App />
        </AtonoProvider>
    );
}
```

Replace `your-customer-id` with the customer identifier used in your application.

Keep the environment key fixed for the session. If the active customer changes, update the context instead of remounting `<AtonoProvider>`.

## Java

The Java SDK doesn’t store evaluation context globally. When a usage event is recorded for a customer or a location, create context for the current request and pass it with the usage record:

```java Java
import io.atono.sdk.context.EvaluationContext;

var context = EvaluationContext.builder()
    .customer("your-customer-id")
    .location(atono.getLocationProvider().fromClientIp(clientIp))
    .build();

boolean isEnabled = atono.getUsageReporter().record(
    "STORY-67",
    context
);
```

Replace:

* `STORY-67` with the story id in Atono
* `your-customer-id` with the customer identifier used in your application
* `clientIp` with the client’s IP address for the current request

Your application is responsible for identifying the appropriate customer and client IP address for the current request. How you manage evaluation context depends on your application architecture. For example, you might cache it for a session or create it for each request.

Pass the client’s IP address, not the IP address of the application server.

The location provider supports IPv4 and IPv6 addresses. If it can’t determine a location from the supplied IP address, the SDK records the usage event without location context.

## Node.js

The Node.js SDK doesn’t store evaluation context globally. When a usage event is recorded for a customer or a location add the evaluation context to the usage record call:

```javascript JavaScript
atono.getUsageReporter().record(
    'STORY-67',
    {
      customer: 'your-customer-id',
      location: atono.getLocationService().fromClientIp(clientIp)
    }
);
```

Replace:

* `STORY-67` with the story id in Atono
* `your-customer-id` with the customer identifier used in your application
* `clientIp` with the client’s IP address for the current request

Your application is responsible for identifying the appropriate customer and client IP address for the current request. How you manage evaluation context depends on your application architecture. For example, you might cache it for a session or create it for each request.

Pass the client’s IP address, not the IP address of the application server.

The location provider supports IPv4 and IPv6 addresses. If it can’t determine a location from the supplied IP address, the SDK records the usage event without location context.

***

# Alternative: Atono Chrome extension

For features used in a browser, you can use the Atono Chrome extension to capture user interactions and associate them with stories instead of adding tracking calls to your code. This approach is useful for product managers or QA who want to map usage without adding new tracking calls to the application code.

The Web or React SDK must still be installed and initialized in the browser. For details, see [Map clicks for usage tracking](https://docs.atono.io/docs/chrome-browser-extension#map-clicks-for-usage-tracking).

The Atono Chrome extension can’t capture actions that occur only in server-side Java code. To track those actions, use the Java SDK and call `record()` in your application.

<br />

***

# Troubleshooting

<Accordion title="Customer not showing in the graph?" icon="fa-info-circle">
  Make sure `customer` is included in the SDK context before calling `record()`.

  Usage events without a customer value appear as **Unknown** in the graph.

  For React, avoid changing the environment key or remounting the `<AtonoProvider>` during renders. Update the context instead.

  For Java and NodeJs, make sure the context passed to `record()` includes the appropriate customer for the current request.
</Accordion>

<Accordion title="Location not showing or seems wrong?" icon="fa-info-circle">
  For the Web and React SDKs, location is detected automatically from the user’s IP address. VPNs and proxies can affect the detected location.

  For Java and NodeJs, make sure you pass the client’s IP address to the location provider. If the SDK can’t determine a location from the address, it records the event without location context.
</Accordion>

<Accordion title="Context shows up intermittently?" icon="fa-info-circle">
  For the Web and React SDKs, this can happen if the SDK is reinitialized during a session. Keep the environment key fixed and set customer context before calling `record()`.

  For Java and NodeJs, make sure the appropriate context is passed with every usage event.
</Accordion>

<Accordion title="No data at all?" icon="fa-info-circle">
  Check the following:

  - The appropriate Atono SDK is installed and initialized
  - For the Web and React SDKs, version 1.1.0 or later is installed
  - A valid story ID is passed to `record()`, such as `STORY-67`
  - The correct environment key is being used
  - For Java and NodeJs, context is passed with the usage event
  - The story is assigned to a team
  - The story is in a workflow step categorized as **In progress** or **Done**
  - The selected date range isn’t excluding recent activity
  - Filters aren’t hiding expected data
</Accordion>