> ## Documentation Index
> Fetch the complete documentation index at: https://docs.trophy.so/llms.txt
> Use this file to discover all available pages before exploring further.

# How To Build An Achievements Feature

> Learn how to use Trophy to add an achievements feature to your web or mobile app.

The guide outlines the full process of adding an achievements feature to your web or mobile app using Trophy.

For illustration purposes we'll use the example of a study platform that uses achievements to incentivize and reward users for viewing flashcards.

<Tip>
  To see a fully working example of this in practice, check out the [live
  demo](https://examples.trophy.so) or [github
  repo](https://github.com/trophyso/example-study-platform/tree/demo).
</Tip>

<h2 id="pre-requisites">
  Pre-requisites
</h2>

* A [Trophy](https://app.trophy.so/sign-up) account
* About 10 minutes

<h2 id="trophy-setup">
  Trophy Setup
</h2>

In Trophy, [Metrics](/features/metrics) are the building blocks of gamification and model the different interactions users make with your product.

In this guide the interaction we're interested in is `flashcards-viewed`, but you can create a metric that best represents the interaction you want to build achievements around.

In the Trophy dashboard, head to the [metrics page](https://app.trophy.so/metrics) and create a metric.

<Frame>
  <video autoPlay muted loop playsInline className="w-full aspect-video" src="https://mintcdn.com/trophy/2khPIyZFxPyE7xgA/assets/guides/achievements-feature/create_new_metric.mp4?fit=max&auto=format&n=2khPIyZFxPyE7xgA&q=85&s=8e66d7276d9648d449c4556340febf45" data-path="assets/guides/achievements-feature/create_new_metric.mp4" />
</Frame>

Once you've created your metric, head to the [achievements page](https://app.trophy.so/achievements) and create the achievements you want. You can find all the details on the types of achievements and the different use cases in the [achievements docs](/features/achievements).

For the purposes of this guide we've set up a couple of achievements based on an increasing number of flashcards flipped:

* 10 flashcards
* 50 flashcards
* 100 flashcards
* 250 flashcards
* 1,000 flashcards

We've also set up a few achievements related to [Streaks](/features/streaks), but we won't go into detail on these in this guide.

<Tip>
  For a full guide on adding a streaks feature to your web or mobile app, check
  out our [full guide](/guides/how-to-build-a-streaks-feature).
</Tip>

In Trophy you track user interactions by sending [Events](/features/events) from your code to Trophy APIs against a specific metric.

When events are recorded for a specific user, any achievements linked to the specified metric will be **completed automatically** if the requirements are met.

This is what makes building gamified experiences with Trophy so easy, it does all the work for you behind the scenes.

<h2 id="installing-trophy-sdk">
  Installing Trophy SDK
</h2>

To interact with Trophy from your code you'll use the Trophy SDK available in most major [programming languages](/api-reference/client-libraries).

Install the Trophy SDK:

<CodeGroup>
  ```bash Node theme={null}
  npm install @trophyso/node
  ```

  ```bash Ruby theme={null}
  gem install trophy_api_client
  ```

  ```bash Python theme={null}
  pip install trophy
  ```

  ```bash PHP theme={null}
  composer require trophyso/php
  ```

  ```bash Java (Gradle) theme={null}
  implementation 'so.trophy:trophy-java:1.0.0'
  ```

  ```bash Java (Maven) theme={null}
  <dependency>
    <groupId>so.trophy</groupId>
    <artifactId>trophy-java</artifactId>
    <version>1.0.0</version>
  </dependency>
  ```

  ```bash Go theme={null}
  go get github.com/trophy-so/trophy-go
  ```

  ```bash .NET (C#) theme={null}
  // .NET Core CLI
  dotnet add package Trophy

  // Nuget Package Manager
  nuget install Trophy

  // Visual Studio
  Install-Package Trophy
  ```
</CodeGroup>

Next, grab your API key from the Trophy [integration page](https://app.trophy.so/integration) and add this as a **server-side only** environment variable.

```bash theme={null}
TROPHY_API_KEY='*******'
```

<Warning>
  Make sure you **don't** expose your API key in client-side code.
</Warning>

<h2 id="tracking-user-interactions">
  Tracking User Interactions
</h2>

To track an event (user interaction) against your metric, use the [metric change API](/api-reference/endpoints/metrics/send-a-metric-change-event).

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://app.trophy.so/api/metrics/flashcards-flipped/event \
       -H "X-API-KEY: <apiKey>" \
       -H "Content-Type: application/json" \
       -d '{
    "user": {
      "id": "18",
      "email": "user@example.com",
      "tz": "Europe/London"
    },
    "value": 750
  }'
  ```

  ```typescript Node theme={null}
  trophy.metrics.event("flashcards-flipped", {
    user: {
      id: "18",
      email: "user@example.com",
      tz: "Europe/London",
    },
    value: 750,
  });
  ```

  ```python Python theme={null}
  client.metrics.event(
      key="flashcards-flipped",
      user=EventRequestUser(
          id="18",
          email="user@example.com",
          tz="Europe/London",
      ),
      value=750.0,
  )
  ```

  ```php PHP theme={null}
  $user = new EventRequestUser([
      'id' => '18',
      'email' => 'user@example.com'
  ]);

  $request = new MetricsEventRequest([
      'user' => $user,
      'value' => 750
  ]);

  $trophy->metrics->event("flashcards-flipped", $request);
  ```

  ```java Java theme={null}
  MetricsEventRequest request = MetricsEventRequest.builder()
        .user(
          EventRequestUser.builder()
            .id("18")
            .email("user@example.com")
            .build()
        )
        .value(750)
        .build();

  EventResponse response = client.metrics().event("flashcards-flipped", request);
  ```

  ```go Go theme={null}
  response, err := client.Metrics.Event(
      "flashcards-flipped",
      &api.MetricsEventRequest{
          User: &api.EventRequestUser{
              Id: "18",
              Email: "user@example.com",
          },
          Value: 750,
      },
  )
  ```

  ```csharp C# theme={null}
  var user = new EventRequestUser {
     Id = "18",
     Email = "user@example.com"
  };

  var request = new MetricsEventRequest {
     User = user,
     Value = 750
  };

  await trophy.Metrics.EventAsync("flashcards-flipped", request);
  ```

  ```ruby Ruby theme={null}
  result = client.metrics.event(
    :key => 'flashcards-flipped',
    :user => {
      :id => '18',
      :email => 'user@example.com'
    },
    :value => 750
  )
  ```
</CodeGroup>

The response to this API call is the complete set of changes to any features you've built with Trophy, including any achievements that were unlocked as a result of the event.

```json Response [expandable] theme={null}
{
  "metricId": "d01dcbcb-d51e-4c12-b054-dc811dcdc623",
  "eventId": "0040fe51-6bce-4b44-b0ad-bddc4e123534",
  "total": 750,
  "achievements": [
    {
      "id": "5100fe51-6bce-6j44-b0hs-bddc4e123682",
      "trigger": "metric",
      "metricId": "5100fe51-6bce-6j44-b0hs-bddc4e123682",
      "metricName": "Flashcards Flipped",
      "metricValue": 500,
      "name": "500 Flashcards Flipped",
      "description": "Write 500 words in the app.",
      "achievedAt": "2020-01-01T00:00:00Z"
    }
  ],
  ...
}
```

Validate this is working by checking the Trophy [dashboard](https://app.trophy.so).

<Frame>
  <img height="200" width="100%" noZoom src="https://mintcdn.com/trophy/2khPIyZFxPyE7xgA/assets/guides/achievements-feature/top-users.png?fit=max&auto=format&n=2khPIyZFxPyE7xgA&q=85&s=bb6f28c04ba9e48d6bf8f93ed1271337" data-path="assets/guides/achievements-feature/top-users.png" />
</Frame>

<h2 id="displaying-achievements">
  Displaying Achievements
</h2>

You have a number of options for displaying achievements in your application. Here we'll look at the most common options.

<h3 id="pop-up-notifications">
  Pop-up Notifications
</h3>

We can use the response of the [metric change API](/api-reference/endpoints/metrics/send-a-metric-change-event) to show pop-up notifications (or 'toasts') when users complete achievements.

Here's an example of this in action:

```ts Achievement Completed Pop-up theme={null}
// Sends event to Trophy
const response = await viewFlashcard();

if (!response) {
  return;
}

// Show toasts if the user has unlocked any new achievements
response.achievements.forEach((achievement) => {
  toast({
    title: achievement.name,
    description: achievement.description,
    image: {
      src: achievement.badgeUrl,
      alt: achievement.name,
    },
  });
});
```

<Frame>
  <video autoPlay muted loop playsInline className="w-full aspect-video" src="https://mintcdn.com/trophy/2khPIyZFxPyE7xgA/assets/guides/achievements-feature/displaying-toasts.mp4?fit=max&auto=format&n=2khPIyZFxPyE7xgA&q=85&s=9735f2e5ac0e72e25aacd43264673b4f" data-path="assets/guides/achievements-feature/displaying-toasts.mp4" />
</Frame>

<Tip>
  If you want to play sound effects, use the [HTML5 Audio
  API](https://developer.mozilla.org/en-US/docs/Web/API/Web_Audio_API) and feel
  free to steal these [audio
  files](https://github.com/trophyso/example-study-platform/tree/demo/public/sounds)
  we recommend.
</Tip>

<h3 id="displaying-user-achievements">
  Displaying User Achievements
</h3>

To fetch all achievements a user has completed, use the [user achievements API](/api-reference/endpoints/users/get-a-users-completed-achievements).

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url https://api.trophy.so/v1/users/{id}/achievements \
    --header 'X-API-KEY: <api-key>'
  ```

  ```typescript Node theme={null}
  trophy.users.achievements("user-id");
  ```

  ```python Python theme={null}
  client.users.achievements("user-id")
  ```

  ```php PHP theme={null}
  $trophy->users->achievements("user-id");
  ```

  ```java Java theme={null}
  UserAchievementsResponse response = client.users().achievements("user-id");
  ```

  ```go Go theme={null}
  response, err := client.Users.Achievements("user-id")
  ```

  ```csharp C# theme={null}
  await trophy.Users.AchievementsAsync("user-id");
  ```

  ```ruby Ruby theme={null}
  result = client.users.achievements(
    :id => 'user-id'
  )
  ```
</CodeGroup>

<Tip>
  You can also fetch incomplete achievements at the same time by passing
  `includeIncomplete` as `'true'`.
</Tip>

<Frame>
  <video autoPlay muted loop playsInline className="w-full aspect-video" src="https://mintcdn.com/trophy/2khPIyZFxPyE7xgA/assets/guides/achievements-feature/displaying_trophy_cabinet.mp4?fit=max&auto=format&n=2khPIyZFxPyE7xgA&q=85&s=987adecfd9abee5294ac6487fe76d402" data-path="assets/guides/achievements-feature/displaying_trophy_cabinet.mp4" />
</Frame>

<h3 id="displaying-all-achievements">
  Displaying All Achievements
</h3>

If instead you want to display all achievements you've set up in Trophy as part of a globally accessible UI that isn't linked to a particular user, you can use the [all achievements API](/api-reference/endpoints/achievements/all-achievements).

<CodeGroup>
  ```bash cURL theme={null}
  curl --request GET \
    --url https://api.trophy.so/v1/achievements \
    --header 'X-API-KEY: <api-key>'
  ```

  ```typescript Node theme={null}
  trophy.achievements();
  ```

  ```python Python theme={null}
  client.achievements()
  ```

  ```php PHP theme={null}
  $trophy->achievements();
  ```

  ```java Java theme={null}
  UserAchievementsResponse response = client.achievements();
  ```

  ```go Go theme={null}
  response, err := client.Achievements()
  ```

  ```csharp C# theme={null}
  await trophy.AchievementsAsync();
  ```

  ```ruby Ruby theme={null}
  result = client.achievements()
  ```
</CodeGroup>

<h3 id="achievement-completion-stats">
  Achievement Completion Stats
</h3>

Both the user achievements API and the all achievements API include completion
statistics like `completions` (the number of users that have completed an
achievement) and `rarity` (the percentage of users that have completed an
achievement).

<Frame>
  <img height="200" width="100%" noZoom src="https://mintcdn.com/trophy/2khPIyZFxPyE7xgA/assets/guides/achievements-feature/completion-stats.png?fit=max&auto=format&n=2khPIyZFxPyE7xgA&q=85&s=bf1d3fc81dbf0631bb477d06660f405c" data-path="assets/guides/achievements-feature/completion-stats.png" />
</Frame>

<h2 id="analytics">
  Analytics
</h2>

The [achievements page](https://app.trophy.so/achievements) in Trophy shows how many users have completed each achievement you've set up.

<Frame>
  <img height="200" width="100%" noZoom src="https://mintcdn.com/trophy/2khPIyZFxPyE7xgA/assets/guides/achievements-feature/check_user_completions.png?fit=max&auto=format&n=2khPIyZFxPyE7xgA&q=85&s=c597555608e7f166887376d94ab648f6" data-path="assets/guides/achievements-feature/check_user_completions.png" />
</Frame>

Additionally the analytics page on any metric in Trophy includes a chart that shows the progress of users through your achievements.

<Frame>
  <img height="200" width="100%" noZoom src="https://mintcdn.com/trophy/2khPIyZFxPyE7xgA/assets/guides/achievements-feature/achievement_completions.png?fit=max&auto=format&n=2khPIyZFxPyE7xgA&q=85&s=5770aaffd83fdecc356167753edfcf0c" data-path="assets/guides/achievements-feature/achievement_completions.png" />
</Frame>

<h2 id="get-support">
  Get Support
</h2>

Want to get in touch with the Trophy team? Reach out to us via [email](mailto:support@trophy.so). We're here to help!
