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

# Post Impressions

> Record post view analytics, read impression and reach counts, and query users who viewed a post.

Post impression analytics has three SDK-facing pieces:

* Mark a post as viewed when your app decides it was visible enough to count.
* Read `impression` and `reach` from the post model returned by retrieval or query APIs.
* Query reached users when you need the list of unique viewers for a post.

<Info>
  The SDK exposes impression and reach counters, but it does not expose a ready-made view-rate metric. Calculate product-specific ratios in your app from the counters and audience size that matter to your experience.
</Info>

## Metrics

| Metric     | TypeScript / iOS / Flutter | Android                | Meaning                                 |
| ---------- | -------------------------- | ---------------------- | --------------------------------------- |
| Impression | `post.impression`          | `post.getImpression()` | Total view events recorded for the post |
| Reach      | `post.reach`               | `post.getReach()`      | Unique users who viewed the post        |

## Platform APIs

| Operation           | TypeScript                                                                 | iOS                                                                   | Android                                                        | Flutter                                                                             |
| ------------------- | -------------------------------------------------------------------------- | --------------------------------------------------------------------- | -------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| Mark viewed         | `post.analytics.markAsViewed()`                                            | `post.analytics.markAsViewed()`                                       | `post.analytics().markAsViewed()`                              | `post.analytics().markPostAsViewed()`                                               |
| Query reached users | `UserRepository.getReachedUsers({ viewId, viewedType: "post" }, callback)` | `userRepository.getReachedUsers(viewedType: .post, viewedId: postId)` | `userRepository.getReachedUsers(AmityViewedType.POST, postId)` | `userRepository.getViewedUsers(viewedType: AmityViewedType.POST, viewedId: postId)` |

## Parameters

| Operation             | Parameter             | Required | Description                                                 |
| --------------------- | --------------------- | -------- | ----------------------------------------------------------- |
| Mark a post as viewed | Post object           | Yes      | Loaded post object whose analytics helper records the view. |
| Query reached users   | `viewId` / `viewedId` | Yes      | Post ID used to query users reached by the post.            |
| Query reached users   | `viewedType`          | Yes      | Viewed type value for posts.                                |
| Query reached users   | `limit`               | No       | TypeScript page size for reached-user results.              |

## Mark a Post as Viewed

Call the analytics method from your own visibility logic, such as a post detail screen opening or a feed cell crossing your viewability threshold. Do not call it from every render or rebuild.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { PostRepository } from "@amityco/ts-sdk";

  const unsubscribe = PostRepository.getPost(
    postId,
    ({ data: post, loading, error }) => {
      if (loading) return;
      if (error) {
        handleError(error);
        return;
      }
      if (!post) return;

      post.analytics.markAsViewed();

      renderResults({
        impression: post.impression,
        reach: post.reach,
      });
    },
  );
  ```

  ```swift iOS theme={null}
  let postRepository = AmityPostRepository()
  var token: AmityNotificationToken?

  token = postRepository.getPost(withId: "post-id").observe { liveObject, error in
      guard let post = liveObject.snapshot else { return }

      post.analytics.markAsViewed()

      let impression = post.impression
      let reach = post.reach
      showSuccessMessage("Impressions: \(impression), reach: \(reach)")
  }
  ```

  ```kotlin Android theme={null}
  postRepository.getPost(postId)
      .subscribe(
          { post ->
              post.analytics().markAsViewed()

              val impression = post.getImpression()
              val reach = post.getReach()
              showSuccessMessage("Impressions: $impression, reach: $reach")
          },
          { error -> handleGeneralError(error) }
      )
  ```

  ```dart Flutter theme={null}
  final subscription = AmitySocialClient.newPostRepository()
      .live
      .getPost(postId)
      .listen((AmityPost post) {
        post.analytics().markPostAsViewed();

        final impression = post.impression ?? 0;
        final reach = post.reach ?? 0;
      });

  await subscription.cancel();
  ```
</CodeGroup>

## Query Reached Users

Use reached-user queries when you need the user list behind the reach count. TypeScript names the ID parameter `viewId`; iOS, Android, and Flutter name it `viewedId`.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { UserRepository } from "@amityco/ts-sdk";

  const unsubscribe = UserRepository.getReachedUsers(
    {
      viewId: postId,
      viewedType: "post",
      limit: 10,
    },
    ({ data: users, loading, error }) => {
      if (loading) return;
      if (error) {
        handleError(error);
        return;
      }

      renderResults(users);
    },
  );
  ```

  ```swift iOS theme={null}
  let userRepository = AmityUserRepository()
  var token: AmityNotificationToken?

  token = userRepository
      .getReachedUsers(viewedType: .post, viewedId: "post-id")
      .observe { collection, error in
          showSuccessMessage(collection.snapshots.count)
      }
  ```

  ```kotlin Android theme={null}
  import com.amity.socialcloud.sdk.model.core.analytics.AmityViewedType

  AmityCoreClient.newUserRepository()
      .getReachedUsers(viewedType = AmityViewedType.POST, viewedId = postId)
      .subscribe(
          { users: PagingData<AmityUser> -> showSuccessMessage(users) },
          { error -> handleGeneralError(error) }
      )
  ```

  ```dart Flutter theme={null}
  final users = await AmityCoreClient.newUserRepository()
      .getViewedUsers(viewedType: AmityViewedType.POST, viewedId: postId)
      .query();

  final reachedUserCount = users.length;
  ```
</CodeGroup>

## Notes

* Keep the unsubscriber, notification token, or stream subscription so you can dispose it when the screen is destroyed.
* Refresh or re-query the post if your UI needs updated `impression` and `reach` values after marking a view.
* Treat analytics failures as non-blocking; viewing a post should not depend on the analytics event being accepted.
* Apply your own viewability threshold and debounce rules before calling the SDK method.

## Related Topics

<CardGroup cols={3}>
  <Card title="Query Posts" icon="filter" href="../retrieval/query-posts">
    Query posts by feed target, post type, review status, or tags
  </Card>

  <Card title="Viewing Content" icon="eye" href="../retrieval/viewing-content">
    Render post data and child media safely
  </Card>

  <Card title="Story Impressions" icon="chart-line" href="../../stories/analytics/story-impressions">
    Track story views and query reached users for stories
  </Card>
</CardGroup>
