> For the complete documentation index, see [llms.txt](https://wiki.playgama.com/playgama/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wiki.playgama.com/playgama/bridge-sdk/api/tasks.md).

# Tasks

{% hint style="info" %}
You are reading the documentation for Bridge SDK **v2**. If you need the obsolete v1 documentation, see [Documentation (v1)](https://wiki.playgama.com/playgama/bridge-sdk-v1).
{% endhint %}

Task system for daily, weekly, and permanent goals ("kill 20 enemies", "collect 100 coins"). The game declares **task groups** in the config, reports gameplay through `addProgress()`, and claims rewards once a task is complete.

## Configuration

Declare task groups in the [config](/playgama/bridge-sdk/config.md) under the `tasks` key. Each group has a `type`: `daily` / `weekly` groups reset every UTC day / week; `permanent` groups never reset. Every item in a group is active for the period.

```json
{
    "tasks": [
        {
            "id": "daily",                 // stable storage key for the group
            "type": "daily",               // 'daily' | 'weekly' | 'permanent'
            "items": [
                {
                    "id": "kills",
                    "targets": [{ "id": "enemy_killed", "amount": 20 }],   // metric id + goal
                    "rewards": [{ "id": "gold", "amount": 500 }]
                },
                {
                    "id": "combo",
                    "targets": [                                            // completes only when ALL targets are met
                        { "id": "kill", "amount": 3 },
                        { "id": "coin", "amount": 100 }
                    ],
                    "rewards": [{ "id": "gem", "amount": 1 }, { "id": "gold", "amount": 50 }]
                }
            ]
        }
    ]
}
```

Groups with an unknown `type` or a missing `id`/`items` are ignored; missing config yields an empty task list.

## Get Tasks

Returns every active task across all groups, with live progress.

{% tabs %}
{% tab title="Plain JS" %}

```javascript
bridge.tasks.getTasks()
    .then(tasks => {
        tasks.forEach(task => {
            console.log(task.id, task.completed, task.claimed)
        })
    })
```

{% endtab %}

{% tab title="Unity" %}

```csharp
private void Start()
{
    Bridge.tasks.GetTasks(OnGetTasksCompleted);
}

private void OnGetTasksCompleted(bool success, List<Task> tasks)
{
    if (success)
    {
        foreach (var task in tasks)
        {
            Debug.Log($"{task.id}, completed: {task.completed}, claimed: {task.claimed}");
        }
    }
}
```

{% endtab %}

{% tab title="Construct 3" %}
Call the `Tasks Get Tasks` action, then handle the `On Tasks Get Tasks Completed` trigger. Read the result with the `TasksCount`, `TaskId`, `TaskType`, `TaskTargetsCount`, `TaskTargetProgress`, `TaskTargetAmount`, `TaskRewardsCount`, `TaskRewardId`, `TaskRewardAmount` expressions, the `Is Task Completed` / `Is Task Claimed` / `Is Task Target Completed` conditions, or take everything at once with `TasksAsJSON`.

<details>

<summary>Copy This Example</summary>

```
{"is-c3-clipboard-data":true,"type":"events","items":[{"eventType":"block","conditions":[{"id":"on-clicked","objectClass":"Button"}],"actions":[{"id":"tasks-get-tasks","objectClass":"PlaygamaBridge"}]},{"eventType":"block","conditions":[{"id":"on-tasks-get-tasks-completed","objectClass":"PlaygamaBridge"}],"actions":[],"children":[{"eventType":"block","conditions":[{"id":"for","objectClass":"System","parameters":{"name":"\"tasks\"","start-index":"0","end-index":"PlaygamaBridge.TasksCount - 1"}}],"actions":[{"id":"log","objectClass":"Browser","parameters":{"type":"log","message":"PlaygamaBridge.TaskId(loopindex(\"tasks\"))"}}],"children":[{"eventType":"block","conditions":[{"id":"is-task-completed","objectClass":"PlaygamaBridge","parameters":{"task-index":"loopindex(\"tasks\")"}}],"actions":[{"type":"comment","text":"task is completed"}]}]}]}]}
```

</details>
{% endtab %}

{% tab title="GDevelop" %}
Call the `Tasks Get Tasks` action, then handle the `On Tasks Get Tasks Completed` condition. Read the result with the `PlaygamaBridge::TasksCount()`, `PlaygamaBridge::TaskId(index)`, `PlaygamaBridge::TaskType(index)`, `PlaygamaBridge::TaskTargetProgress(index, targetIndex)`, `PlaygamaBridge::TaskTargetAmount(index, targetIndex)`, `PlaygamaBridge::TaskRewardId(index, rewardIndex)`, `PlaygamaBridge::TaskRewardAmount(index, rewardIndex)` expressions, the `Is Task Completed` / `Is Task Claimed` conditions, or take everything at once with `PlaygamaBridge::TasksAsJSON()`.

<details>

<summary>Copy This Example</summary>

```
{"000kind":"GDEVELOP_EventsAndInstructions_CLIPBOARD_KIND-jsBdHbLy912y8Rc","content":{"eventsList":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"PanelSpriteButton::PanelSpriteButton::IsClicked"},"parameters":["Button",""]}],"actions":[{"type":{"value":"PlaygamaBridge::TasksGetTasks"},"parameters":["",""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"PlaygamaBridge::OnTasksGetTasksCompleted"},"parameters":["",""]}],"actions":[{"type":{"value":"SetNumberVariable"},"parameters":["CurrentIndex","=","0"]}],"events":[{"type":"BuiltinCommonInstructions::Repeat","repeatExpression":"PlaygamaBridge::TasksCount()","conditions":[],"actions":[],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["PlaygamaBridge::TaskId(CurrentIndex)","\"info\"",""]},{"type":{"value":"SetNumberVariable"},"parameters":["CurrentIndex","+","1"]}]}]}]}],"eventsCount":2,"actionsList":[],"actionsCount":0,"conditionsList":[],"conditionsCount":0}}
```

</details>
{% endtab %}

{% tab title="Godot" %}
{% tabs %}
{% tab title="Godot 3.x" %}

```gdscript
func _ready():
    Bridge.tasks.get_tasks(funcref(self, "_on_get_tasks_completed"))

func _on_get_tasks_completed(success, tasks):
    if success:
        for task in tasks:
            print(task.id, " completed: ", task.completed, " claimed: ", task.claimed)
```

{% endtab %}

{% tab title="Godot 4.x" %}

```gdscript
func _ready():
    Bridge.tasks.get_tasks(Callable(self, "_on_get_tasks_completed"))

func _on_get_tasks_completed(success, tasks):
    if success:
        for task in tasks:
            print(task.id, " completed: ", task.completed, " claimed: ", task.claimed)
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="GameMaker" %}

```javascript
playgama_bridge_tasks_get_tasks()

// callback via Async Social Event
if async_load[? "type"] == "playgama_bridge_tasks_get_tasks_callback" {
    if async_load[? "success"] {
        var tasks = json_parse(async_load[? "data"])
        for (var i = 0; i < array_length(tasks); i += 1) {
            var task = tasks[i]
            // task.id, task.completed, task.claimed
        }
    }
}
```

{% endtab %}

{% tab title="Defold" %}

```lua
local bridge = require("bridge.bridge")

function init(self)
    bridge.tasks.get_tasks(
        function (_, tasks_json)
            local tasks = json.decode(tasks_json)
            for _, task in ipairs(tasks) do
                print(task.id, task.completed, task.claimed)
            end
        end,
        function ()
            -- error
        end
    )
end
```

{% endtab %}

{% tab title="Cocos Creator" %}

```javascript
bridge.tasks.getTasks()
    .then(tasks => {
        tasks.forEach(task => {
            console.log(task.id, task.completed, task.claimed)
        })
    })
```

{% endtab %}
{% endtabs %}

A `Task` looks like this:

```javascript
{
    id: 'kills',
    type: 'daily',                  // group type
    targets: [
        { id: 'enemy_killed', amount: 20, progress: 12, completed: false }
    ],
    rewards: [
        { id: 'gold', amount: 500 }
    ],
    completed: false,               // true once every target is met
    claimed: false
}
```

## Add Progress

Report a gameplay metric. Every active target watching that metric advances by `amount` (default `1`), across all groups and types at once, clamped to the target's goal. An unwatched metric is a no-op.

{% tabs %}
{% tab title="Plain JS" %}

```javascript
await bridge.tasks.addProgress('enemy_killed')      // +1
await bridge.tasks.addProgress('coin_collected', 5) // +5
```

{% endtab %}

{% tab title="Unity" %}

```csharp
Bridge.tasks.AddProgress("enemy_killed");      // +1
Bridge.tasks.AddProgress("coin_collected", 5); // +5
```

{% endtab %}

{% tab title="Construct 3" %}
Call the `Tasks Add Progress` action with the metric id and amount, then handle the `On Tasks Add Progress Completed` trigger.

<details>

<summary>Copy This Example</summary>

```
{"is-c3-clipboard-data":true,"type":"events","items":[{"eventType":"block","conditions":[{"id":"on-clicked","objectClass":"Button"}],"actions":[{"id":"tasks-add-progress","objectClass":"PlaygamaBridge","parameters":{"metric":"\"enemy_killed\"","amount":"1"}}]},{"eventType":"block","conditions":[{"id":"on-tasks-add-progress-completed","objectClass":"PlaygamaBridge"}],"actions":[],"children":[{"eventType":"block","conditions":[{"id":"is-last-action-completed-successfully","objectClass":"PlaygamaBridge"}],"actions":[{"type":"comment","text":"success"}]}]}]}
```

</details>
{% endtab %}

{% tab title="GDevelop" %}
Call the `Tasks Add Progress` action with the metric id and amount, then handle the `On Tasks Add Progress Completed` condition.

<details>

<summary>Copy This Example</summary>

```
{"000kind":"GDEVELOP_EventsAndInstructions_CLIPBOARD_KIND-jsBdHbLy912y8Rc","content":{"eventsList":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"PanelSpriteButton::PanelSpriteButton::IsClicked"},"parameters":["Button",""]}],"actions":[{"type":{"value":"PlaygamaBridge::TasksAddProgress"},"parameters":["","\"enemy_killed\"","1",""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"PlaygamaBridge::OnTasksAddProgressCompleted"},"parameters":["",""]}],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"PlaygamaBridge::IsLastActionCompletedSuccessfully"},"parameters":["",""]}],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"success\"","\"info\"",""]}]}],"actions":[]}],"eventsCount":2,"actionsList":[],"actionsCount":0,"conditionsList":[],"conditionsCount":0}}
```

</details>
{% endtab %}

{% tab title="Godot" %}
{% tabs %}
{% tab title="Godot 3.x" %}

```gdscript
Bridge.tasks.add_progress("enemy_killed", 1, funcref(self, "_on_add_progress_completed"))

func _on_add_progress_completed(success):
    print(success)
```

{% endtab %}

{% tab title="Godot 4.x" %}

```gdscript
Bridge.tasks.add_progress("enemy_killed", 1, Callable(self, "_on_add_progress_completed"))

func _on_add_progress_completed(success):
    print(success)
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="GameMaker" %}

```javascript
playgama_bridge_tasks_add_progress("enemy_killed", 1)

// callback via Async Social Event
if async_load[? "type"] == "playgama_bridge_tasks_add_progress_callback" {
    if async_load[? "success"] {
        // your logic
    }
}
```

{% endtab %}

{% tab title="Defold" %}

```lua
local bridge = require("bridge.bridge")

function init(self)
    bridge.tasks.add_progress(
        "enemy_killed",
        1,
        function ()
            -- success
        end,
        function ()
            -- error
        end
    )
end
```

{% endtab %}

{% tab title="Cocos Creator" %}

```javascript
await bridge.tasks.addProgress('enemy_killed')      // +1
await bridge.tasks.addProgress('coin_collected', 5) // +5
```

{% endtab %}
{% endtabs %}

`addProgress()` resolves to `void` — read completion back via `getTasks()`.

## Claim Reward

Marks a completed task's rewards as claimed. Resolves to `true` on success, or `false` when the task is not currently active, not yet complete, or already claimed. It does **not** return the rewards — read them from the task's `rewards` via `getTasks()`.

{% tabs %}
{% tab title="Plain JS" %}

```javascript
bridge.tasks.claimReward(id)
    .then(() => {
        // grant the task's rewards
    })
```

{% endtab %}

{% tab title="Unity" %}

```csharp
Bridge.tasks.ClaimReward(id, claimed =>
{
    if (claimed)
    {
        // grant the task's rewards
    }
});
```

{% endtab %}

{% tab title="Construct 3" %}
Call the `Tasks Claim Reward` action with the task id, then handle the `On Tasks Claim Reward Completed` trigger — `Is Last Action Completed Successfully` is true only when the reward was actually claimed. Read the rewards to grant with the `TaskRewardId` / `TaskRewardAmount` expressions after `Tasks Get Tasks`.

<details>

<summary>Copy This Example</summary>

```
{"is-c3-clipboard-data":true,"type":"events","items":[{"eventType":"block","conditions":[{"id":"on-clicked","objectClass":"Button"}],"actions":[{"id":"tasks-claim-reward","objectClass":"PlaygamaBridge","parameters":{"task-id":"\"kills\""}}]},{"eventType":"block","conditions":[{"id":"on-tasks-claim-reward-completed","objectClass":"PlaygamaBridge"}],"actions":[],"children":[{"eventType":"block","conditions":[{"id":"is-last-action-completed-successfully","objectClass":"PlaygamaBridge"}],"actions":[{"type":"comment","text":"claimed - grant the task's rewards"}]}]}]}
```

</details>
{% endtab %}

{% tab title="GDevelop" %}
Call the `Tasks Claim Reward` action with the task id, then handle the `On Tasks Claim Reward Completed` condition — `Is Last Action Completed Successfully` is true only when the reward was actually claimed. Read the rewards to grant with the `PlaygamaBridge::TaskRewardId(...)` / `PlaygamaBridge::TaskRewardAmount(...)` expressions after `Tasks Get Tasks`.

<details>

<summary>Copy This Example</summary>

```
{"000kind":"GDEVELOP_EventsAndInstructions_CLIPBOARD_KIND-jsBdHbLy912y8Rc","content":{"eventsList":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"PanelSpriteButton::PanelSpriteButton::IsClicked"},"parameters":["Button",""]}],"actions":[{"type":{"value":"PlaygamaBridge::TasksClaimReward"},"parameters":["","\"kills\"",""]}]},{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"PlaygamaBridge::OnTasksClaimRewardCompleted"},"parameters":["",""]}],"events":[{"type":"BuiltinCommonInstructions::Standard","conditions":[{"type":{"value":"PlaygamaBridge::IsLastActionCompletedSuccessfully"},"parameters":["",""]}],"actions":[{"type":{"value":"DebuggerTools::ConsoleLog"},"parameters":["\"claimed\"","\"info\"",""]}]}],"actions":[]}],"eventsCount":2,"actionsList":[],"actionsCount":0,"conditionsList":[],"conditionsCount":0}}
```

</details>
{% endtab %}

{% tab title="Godot" %}
{% tabs %}
{% tab title="Godot 3.x" %}

```gdscript
Bridge.tasks.claim_reward(id, funcref(self, "_on_claim_reward_completed"))

func _on_claim_reward_completed(claimed):
    if claimed:
        # grant the task's rewards
        pass
```

{% endtab %}

{% tab title="Godot 4.x" %}

```gdscript
Bridge.tasks.claim_reward(id, Callable(self, "_on_claim_reward_completed"))

func _on_claim_reward_completed(claimed):
    if claimed:
        # grant the task's rewards
        pass
```

{% endtab %}
{% endtabs %}
{% endtab %}

{% tab title="GameMaker" %}

```javascript
playgama_bridge_tasks_claim_reward(id)

// callback via Async Social Event
if async_load[? "type"] == "playgama_bridge_tasks_claim_reward_callback" {
    if async_load[? "success"] {
        // claimed - grant the task's rewards
    }
}
```

{% endtab %}

{% tab title="Defold" %}

```lua
local bridge = require("bridge.bridge")

function init(self)
    bridge.tasks.claim_reward(
        id,
        function ()
            -- claimed, grant the task's rewards
        end,
        function ()
            -- not claimed or error
        end
    )
end
```

{% endtab %}

{% tab title="Cocos Creator" %}

```javascript
bridge.tasks.claimReward(id)
    .then(() => {
        // grant the task's rewards
    })
```

{% endtab %}
{% endtabs %}
