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

# Activity

> Read a user's tracked in-game minutes over a time range, optionally scoped to a place.

export const badgeStyle = {
  display: 'inline-block',
  padding: '2px 10px',
  borderRadius: '9999px',
  fontSize: '12px',
  fontWeight: 600,
  lineHeight: '20px',
  marginRight: '6px',
  verticalAlign: 'middle'
};

export const V2 = () => <span style={{
  ...badgeStyle,
  backgroundColor: 'rgba(88, 101, 242, 0.15)',
  color: '#5865F2',
  border: '1px solid rgba(88, 101, 242, 0.4)'
}}>V2 · Batchable</span>;

export const GameApi = () => <span style={{
  ...badgeStyle,
  backgroundColor: 'rgba(245, 158, 11, 0.15)',
  color: '#D97706',
  border: '1px solid rgba(245, 158, 11, 0.4)'
}}>Requires Org Functions</span>;

BloxCord records tracked playtime for every member. These methods let your game
read those totals in real time.

## getUserMinutes

<V2 />

<GameApi />

Returns a user's tracked minutes over a time range, optionally scoped to a
single place.

```lua theme={null}
local result = BloxCord:Invoke("getUserMinutes", userId, filters)
```

<Note>
  Batchable as the `minutes.get` op with args `{ userId, placeId, timeStart, timeEnd }`
  — see [`apiBatch`](/reference/webhooks-batch#apibatch).
</Note>

### Parameters

<ParamField body="userId" type="number | string" required>
  The `UserId` whose minutes to fetch.
</ParamField>

<ParamField body="filters" type="table">
  Optional filters.

  <Expandable title="filters fields">
    <ParamField body="placeId" type="number | string">
      Restrict the total to minutes earned on this specific place. Omit to count
      minutes across all of your organization's places.
    </ParamField>

    <ParamField body="timeStart" type="number">
      Start of the range, in **unix seconds** (inclusive). Defaults to `0`
      (the beginning of tracking).
    </ParamField>

    <ParamField body="timeEnd" type="number">
      End of the range, in **unix seconds** (exclusive). Defaults to now.
    </ParamField>
  </Expandable>
</ParamField>

### Returns

<ResponseField name="result" type="table | nil">
  A totals table, or `nil` if the request was rejected or the backend was
  unreachable.

  <Expandable title="result fields">
    <ResponseField name="minutes" type="number">Total tracked minutes (including AFK).</ResponseField>
    <ResponseField name="afk" type="number">Minutes counted as AFK.</ResponseField>
    <ResponseField name="active" type="number">Active minutes (`minutes` − `afk`).</ResponseField>
  </Expandable>
</ResponseField>

### Examples

<CodeGroup>
  ```lua This place, last 7 days theme={null}
  local BloxCord = game:WaitForChild("BloxCord")

  local now = os.time()
  local result = BloxCord:Invoke("getUserMinutes", player.UserId, {
      placeId = game.PlaceId,
      timeStart = now - (7 * 24 * 60 * 60),
      timeEnd = now,
  })

  if result and result.active < 60 then
      print(player.Name .. " has under an hour of active playtime this week.")
  end
  ```

  ```lua All places, all time theme={null}
  local BloxCord = game:WaitForChild("BloxCord")

  local result = BloxCord:Invoke("getUserMinutes", player.UserId, {})
  if result then
      print(("%s: %d total, %d active"):format(player.Name, result.minutes, result.active))
  end
  ```
</CodeGroup>

***

## getLeaderboard

<V2 />

<GameApi />

Returns a playtime leaderboard over a time range, optionally scoped to specific
group ranks or a specific set of users.

```lua theme={null}
local result = BloxCord:Invoke("getLeaderboard", filters)
```

<Note>
  Batchable as the `leaderboard.get` op with args
  `{ timeStart, timeEnd, includeAFK, ranks, userIds }` — see
  [`apiBatch`](/reference/webhooks-batch#apibatch).
</Note>

### Parameters

<ParamField body="filters" type="table" required>
  Leaderboard options.

  <Expandable title="filters fields">
    <ParamField body="timeStart" type="number" required>
      Start of the range, in **unix seconds** (inclusive).
    </ParamField>

    <ParamField body="timeEnd" type="number" required>
      End of the range, in **unix seconds** (exclusive). The range cannot exceed
      **5 years**.
    </ParamField>

    <ParamField body="includeAFK" type="boolean" default="false">
      Whether AFK minutes count toward each member's score.
    </ParamField>

    <ParamField body="ranks" type="number[]">
      Group ranks to include. Ignored when `userIds` is provided.
    </ParamField>

    <ParamField body="userIds" type="string[]">
      Specific user ids to include. Takes precedence over `ranks`; the response
      contains exactly these members.
    </ParamField>
  </Expandable>
</ParamField>

### Returns

<ResponseField name="result" type="table | nil">
  A leaderboard payload, or `nil` if the request was rejected (e.g. range over
  5 years) or the backend was unreachable.

  <Expandable title="result fields">
    <ResponseField name="includeAFK" type="boolean">Whether AFK minutes were counted.</ResponseField>
    <ResponseField name="count" type="number">Number of rows returned.</ResponseField>

    <ResponseField name="leaderboard" type="object[]">
      Ranked rows. Open (rank/all) queries return the top 100; explicit `userIds`
      queries return exactly the requested members.

      <Expandable title="row fields">
        <ResponseField name="position" type="number">1-based position in the returned list.</ResponseField>
        <ResponseField name="id" type="string">The member's `UserId`.</ResponseField>
        <ResponseField name="rank" type="number | null">Their most recent group rank in the range.</ResponseField>
        <ResponseField name="minutes" type="number">Total tracked minutes (including AFK).</ResponseField>
        <ResponseField name="afk" type="number">Minutes counted as AFK.</ResponseField>
        <ResponseField name="active" type="number">Active minutes (`minutes` − `afk`).</ResponseField>
        <ResponseField name="value" type="number">The scored value (`minutes` when `includeAFK`, else `active`).</ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

### Example

<CodeGroup>
  ```lua Top players by rank theme={null}
  local BloxCord = game:WaitForChild("BloxCord")

  -- Top active players over the last 30 days, limited to two ranks.
  local now = os.time()
  local result = BloxCord:Invoke("getLeaderboard", {
      timeStart = now - (30 * 24 * 60 * 60),
      timeEnd = now,
      includeAFK = false,
      ranks = { 100, 200 },
  })

  for _, row in ipairs(result and result.leaderboard or {}) do
      print(row.position, row.id, row.active .. " min")
  end
  ```

  ```lua Compare a specific set of users theme={null}
  local BloxCord = game:WaitForChild("BloxCord")

  local now = os.time()
  local result = BloxCord:Invoke("getLeaderboard", {
      timeStart = now - (7 * 24 * 60 * 60),
      timeEnd = now,
      includeAFK = true,
      userIds = { "123456789", "987654321", "111111111" },
  })

  for _, row in ipairs(result and result.leaderboard or {}) do
      print(row.position, row.id, row.value .. " min")
  end
  ```
</CodeGroup>
