# Tokens

Tokens are typed variables that can be used throughout a Flow. A token is either:

* **Local** — Attached to a Flow's trigger card, for example the name of the user that came home.
* **Global** — Available anywhere, for example the current time.

Both tokens can be used in a Flow card's argument, such as a textfield.

![](https://998911913-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-MPk9cn4V7WnnKt7fbry%2Fuploads%2Fgit-blob-531cc8f95cc40535b64490f8cf7910f6b1ce09df%2FTokens.png?alt=media)

{% hint style="info" %}
In the User Interface, tokens are called *Tags.*
{% endhint %}

## Local Tokens

When triggering a Flow, some information might be useful to use in that Flow. For example, when it starts raining, the *mm/hour* could be a token.

Tokens have a pre-defined `type`, which can be either `string`, `number`, `boolean` or `image`.

Users can use Flow Tokens in compatible Flow Arguments, such as a *text* field for `string` tokens. This way, the user can make advanced flows with variables. To add tokens to a Flow card, just add a property `tokens` to your Flow card manifest.

{% hint style="info" %}
A Flow card can also have a`droptoken` field, droptokens are Flow Arguments that require the input to be a token. You can read more about droptokens in the [Flow Arguments documentation](https://apps.developer.homey.app/the-basics/arguments#droptoken).
{% endhint %}

{% code title="/.homeycompose/flow/triggers/rain\_start.json" %}

```javascript
{
  "title": { "en": "It starts raining" },
  "tokens": [
    {
      "name": "mm_per_hour",
      "type": "number",
      "title": { "en": "mm/h" },
      "example": 5
    },
    {
      "name": "city",
      "type": "string",
      "title": { "en": "City" },
      "example": { "en": "Amsterdam" }
    }
  ]
}
```

{% endcode %}

And when firing your trigger, add them as argument:

{% tabs %}
{% tab title="JavaScript" %}
{% code title="/app.js" %}

```javascript
const Homey = require('homey');
const RainApi = require('rain-api');

class App extends Homey.App {
  async onInit() {
    const rainStartTrigger = this.homey.flow.getTriggerCard("rain_start");

    RainApi.on('raining', (city, amount) => {
      const tokens = {
        mm_per_hour: amount,
        city: city
      };

      rainStartTrigger.trigger(tokens)
        .then(this.log)
        .catch(this.error);
    });
  }
}

module.exports = App;
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="/app.mts" %}

```mts
import Homey from "homey";
import RainApi from "rain-api";

export default class App extends Homey.App {
  async onInit(): Promise<void> {
    const rainStartTrigger = this.homey.flow.getTriggerCard("rain_start");

    RainApi.on("raining", (city: string, amount: number) => {
      const tokens = {
        mm_per_hour: amount,
        city: city
      };

      rainStartTrigger.trigger(tokens)
        .then(this.log)
        .catch(this.error);
    });
  }
}

```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code title="/app.py" %}

```python
from homey import app

from rain_api import RainApi


class App(app.App):
    async def on_init(self) -> None:
        rain_start_trigger = self.homey.flow.get_trigger_card("rain_start")

        async def on_raining(city: str, amount: float) -> None:
            tokens = {
                "mm_per_hour": amount,
                "city": city
            }
            try:
                self.log(await rain_start_trigger.trigger(tokens))
            except Exception as e:
                self.error(e)

        RainApi.on("raining", on_raining)


homey_export = App

```

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

### Tokens for Advanced Flow

A Then-card can optionally return tokens in an [Advanced Flow](https://homey.app/advanced-flow/). Similar to a When-card, specify the `tokens` property as an `array`, and return an `object` in the run-listener of your Flow card.

```json
{
  "title": {
    "en": "Make it stop raining"
  },
  "hint": {
    "en": "Hires a shaman to do a sunny dance. Might cost some money."
  },
  "tokens": [
    {
      "name": "shamanName",
      "type": "string",
      "title": {
        "en": "Name of the Shaman"
      }
    },
    {
      "name": "shamanCost",
      "type": "number",
      "title": {
        "en": "Cost of the Shaman (€)"
      }
    }
  ]
}
```

{% tabs %}
{% tab title="JavaScript" %}
{% code title="/app.js" %}

```javascript
    const stopRainingAction = this.homey.flow.getActionCard('stop_raining');
    stopRainingAction.registerRunListener(async (args, state) => {
      await RainApi.makeItStopRaining();
      
      // Return the Tokens for Advanced Flow
      return {
        shamanName: 'Alumbrada',
        shamanCost: 10,
      };
    });
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="/app.mts" %}

```mts
    type StopRainingTokens = {
      shamanName: string;
      shamanCost: number;
    };
    const stopRainingAction = this.homey.flow.getActionCard("stop_raining");
    stopRainingAction.registerRunListener(async (args, state): Promise<StopRainingTokens> => {
      await RainApi.makeItStopRaining();

      // Return the Tokens for Advanced Flow
      return {
        shamanName: "Alumbrada",
        shamanCost: 10,
      };
    });
```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code title="/app.py" %}

```python
from homey import app

from rain_api import RainApi


class App(app.App):
    async def on_init(self) -> None:
        stop_raining_action = self.homey.flow.get_action_card("stop_raining")

        async def run_listener(card_arguments, **trigger_kwargs) -> dict:
            await RainApi.make_it_stop_raining()

            # Return the Tokens for Advanced Flow
            return {
                "shamanName": "Alumbrada",
                "shamanCost": 10,
            }

        stop_raining_action.register_run_listener(run_listener)


homey_export = App

```

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

{% hint style="info" %}
When specifying a `tokens` array in your Then-card's JSON, that card will not be visible when creating & editing a standard Flow.
{% endhint %}

## Global Tokens

A token can also be registered globally, so they can be used in any Flow. This means the token can be used without requiring the app to trigger the Flow. For example a weather app could expose the current temperature as a global token.

By default a device's capability are registered as global tokens.

{% tabs %}
{% tab title="JavaScript" %}
{% code title="/app.js" %}

```javascript
const Homey = require('homey');

class App extends Homey.App {
  async onInit() {
    const myToken = await this.homey.flow.createToken("my_token", {
      type: "number",
      title: "My Token",
    });

    await myToken.setValue(23.5);
  }
}

module.exports = App;
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="/app.mts" %}

```mts
import Homey from "homey";

export default class App extends Homey.App {
  async onInit(): Promise<void> {
    const myToken = await this.homey.flow.createToken("my_token", {
      type: "number",
      title: "My Token",
    });

    await myToken.setValue(23.5);
  }
}

```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code title="/app.py" %}

```python
from homey import app


class App(app.App):
    async def on_init(self) -> None:
        my_token = await self.homey.flow.create_token("my_token", "number", "My Token")

        await my_token.set_value(23.5)


homey_export = App

```

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

## Image Tokens

Certain applications might want to share images between Flows, e.g. a webcam that made a snapshot, or a Chromecast that wants to cast an image. A token with type `image` can be used here.

{% tabs %}
{% tab title="JavaScript" %}
{% code title="/app.js" %}

```javascript
const Homey = require('homey');

class App extends Homey.App {
  async onInit() {
    const myImage = await this.homey.images.createImage();
    myImage.setPath(path.join(__dirname, "assets", "images", "kitten.jpg"));

    // create a token & register it
    const myImageToken = await this.homey.flow.createToken("my_token", {
      type: "image",
      title: "My Image Token",
    });

    await myImageToken.setValue(myImage);

    // listen for a Flow action
    const myActionCard = this.homey.flow.getActionCard("image_action");

    myActionCard.registerRunListener(async (args, state) => {
      // get the contents of the image
      const imageStream = await args.droptoken.getStream();
      this.log(`saving ${imageStream.meta.contentType} to: ${imageStream.meta.filename}`);

      // save the image
      const targetFile = fs.createWriteStream(
        path.join("/userdata", imageStream.meta.filename)
      );
      imageStream.pipe(targetFile);
      return true;
    });

    const myTriggerCard = this.homey.flow.getTriggerCard("image_trigger");

    // pass the image to the trigger call
    await myTriggerCard.trigger({ my_image: myImage });
  }
}

module.exports = App;
```

{% endcode %}
{% endtab %}

{% tab title="TypeScript" %}
{% code title="/app.mts" %}

```mts
import Homey, { type Image } from "homey";
import path from "node:path";
import * as fs from "node:fs";

type ImageActionArgs = {
  droptoken: Image;
};

export default class App extends Homey.App {
  async onInit(): Promise<void> {
    const myImage = await this.homey.images.createImage();
    myImage.setPath(path.join(__dirname, "assets", "images", "kitten.jpg"));

    // create a token & register it
    const myImageToken = await this.homey.flow.createToken("my_token", {
      type: "image",
      title: "My Image Token",
      value: myImage,
    });

    // listen for a Flow action
    const myActionCard = this.homey.flow.getActionCard("image_action");

    myActionCard.registerRunListener(async (args: ImageActionArgs, state) => {
      // get the contents of the image
      const imageStream = await args.droptoken.getStream();
      this.log(`saving ${imageStream.meta.contentType} to: ${imageStream.meta.filename}`);

      // save the image
      const targetFile = fs.createWriteStream(path.join("/userdata", imageStream.meta.filename));
      imageStream.pipe(targetFile);
      return true;
    });

    const myTriggerCard = this.homey.flow.getTriggerCard("image_trigger");

    // pass the image to the trigger call
    await myTriggerCard.trigger({ my_image: myImage });
  }
}

```

{% endcode %}
{% endtab %}

{% tab title="Python" %}
{% code title="/app.mts" %}

```python
import os
from typing import TypedDict

from homey import app
from homey.image import Image


class ImageActionArgs(TypedDict):
    droptoken: Image


class App(app.App):
    async def on_init(self) -> None:
        my_image = await self.homey.images.create_image()
        my_image.set_path(
            os.path.join(os.path.dirname(__file__), "assets", "images", "kitten.jpg")
        )

        my_image_token = await self.homey.flow.create_token(
            "my_token", "image", "My Image Token", my_image
        )

        my_action_card = self.homey.flow.get_action_card("image_action")

        async def run_listener(card_arguments: ImageActionArgs, **trigger_kwargs):
            image_stream = await card_arguments.get("droptoken").get_stream()
            self.log(
                f"saving {image_stream['meta']['contentType']} to {image_stream['meta']['filename']}"
            )

            # save the image
            with open(
                os.path.join("/userdata", image_stream["meta"]["filename"]), "wb"
            ) as target_file:
                target_file.write(image_stream["data"].buffer.read())

        my_action_card.register_run_listener(run_listener)

        my_trigger_card = self.homey.flow.get_trigger_card("image_trigger")
        # pass the image to the trigger call
        await my_trigger_card.trigger({"my_image": my_image})


homey_export = App

```

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