Unofficial custom integration for the tester APIs of Tryber (AppQuality). Exposes your earnings, experience points, monthly ranking and available campaigns as sensors, and notifies you when a new applicable campaign appears.
- HACS > Integrations > top-right menu > Custom repositories
- URL
https://github.com/xPudda/TryberHA, category Integration - Search for Tryber, install and restart Home Assistant
- Copy the
custom_components/tryberfolder to/config/custom_components/ - Restart Home Assistant
- Settings > Devices & services > Add integration > Tryber
- Enter your username (e.g.
first-last) and password
The username is the account one, it doesn't always match the email.
- Login via
POST /authenticatewith username and password - The bearer token is kept in memory and reused until expiry (the API issues it with a 24h validity)
- Automatic renewal 10 minutes before expiry, plus an immediate retry
on a
401mid-refresh - If the password changes, HA starts the re-authentication flow
Your password is needed at every token renewal, so Home Assistant keeps it in
the config entry, unencrypted, in /config/.storage/core.config_entries —
as it does for every integration. Anyone who can read that folder, or an
unencrypted backup of it, can read the password.
Recommended:
- Use a password unique to Tryber
- Keep Home Assistant backups encrypted
- Restrict access to the configuration folder
Every 2 minutes, with 6 parallel calls: users/me (selected fields),
users/me/rank, three queries on users/me/campaigns (applicable, accepted,
active) and one on users/me/bugs.
Home Assistant builds the entity IDs from the device name and the entity name,
following Settings > System > Entity ID format. With the default format and
the default device name Tryber First Last you get
sensor.tryber_first_last_net_earnings; rename the device to Tryber if you
prefer the shorter sensor.tryber_net_earnings.
| Entity | Entity ID suffix | Description |
|---|---|---|
| Net earnings | net_earnings |
Already paid out earnings (net) |
| Gross earnings | gross_earnings |
Already paid out earnings (gross) |
| Net pending earnings | net_pending_earnings |
Accrued but not yet paid (net) |
| Gross pending earnings | gross_pending_earnings |
Accrued but not yet paid (gross) |
| Payout threshold | payout_threshold |
Minimum threshold to request payout |
| Experience points | experience_points |
Total experience points |
| Approved bugs | approved_bugs |
Approved bugs |
| Attended campaigns | attended_campaigns |
Campaigns you took part in |
| Ranking position | ranking_position |
Position in the monthly ranking |
| Monthly level | monthly_level |
Current level (Bronze, Gold...) |
| Monthly points | monthly_points |
Points for the current month |
| Points to next level | points_to_next_level |
Points missing to the next level |
| Available campaigns | available_campaigns |
Campaigns you can apply to |
| Accepted campaigns | accepted_campaigns |
Campaigns you've been selected for |
| Active campaigns | active_campaigns |
Campaigns you're selected for that are still running |
| Latest available campaign | latest_available_campaign |
Name of the most recent applicable one |
| Payout threshold reached | payout_threshold_reached |
binary_sensor, on when you can cash out |
| Bug info requested | bug_info_requested |
binary_sensor, on when at least one of your bugs needs more info |
Changing the entity ID format only affects newly created entities: the ones you already have keep their current ID. Entity names are in English and are not translated.
The examples below use the short entity IDs: replace them with yours.
automation:
- alias: "Tryber - can cash out"
triggers:
- trigger: state
entity_id: binary_sensor.tryber_payout_threshold_reached
to: "on"
actions:
- action: notify.mobile_app_iphone_16
data:
title: "Tryber"
message: >-
Threshold reached: {{ states('sensor.tryber_net_pending_earnings') }} EUR
available to request.
- alias: "Tryber - new campaigns available"
triggers:
- trigger: numeric_state
entity_id: sensor.tryber_available_campaigns
above: 0
actions:
- action: notify.mobile_app_iphone_16
data:
message: >-
There are {{ states('sensor.tryber_available_campaigns') }} campaigns available.
- alias: "Tryber - a bug needs more info"
triggers:
- trigger: state
entity_id: binary_sensor.tryber_bug_info_requested
to: "on"
actions:
- action: notify.mobile_app_iphone_16
data:
title: "Tryber"
message: >-
{{ state_attr('binary_sensor.tryber_bug_info_requested', 'count') }}
bug(s) waiting for more info from you.The integration queries /users/me/campaigns and keeps only the campaigns
with visibility.type == "available", i.e. the ones you can actually
apply to (the others are candidate or unavailable).
When an id that was never seen before appears, the
tryber_new_campaign event is fired on the bus with this data:
| Field | Content |
|---|---|
id |
Campaign id |
name |
Campaign name |
start_date / end_date |
Campaign dates |
close_date |
Application deadline |
free_spots / total_spots |
Free and total spots |
applied |
Whether you've already applied |
Already-seen ids are persisted to disk: after an HA restart you won't get notified again for already-known campaigns. On the very first startup nothing is notified, only the starting state is recorded.
automation:
- alias: "Tryber - new campaign available"
triggers:
- trigger: event
event_type: tryber_new_campaign
actions:
- action: notify.mobile_app_iphone_16
data:
title: "New Tryber campaign"
message: >-
{{ trigger.event.data.name }}
{% if trigger.event.data.free_spots is not none %}
- {{ trigger.event.data.free_spots }} free spots
{% endif %}
{% if trigger.event.data.close_date %}
(apply by {{ trigger.event.data.close_date }})
{% endif %}
data:
url: "https://app.tryber.me/campaigns/{{ trigger.event.data.id }}"
push:
interruption-level: time-sensitiveA variant that only notifies if there are free spots:
conditions:
- condition: template
value_template: >-
{{ trigger.event.data.free_spots is none
or trigger.event.data.free_spots > 0 }}sensor.tryber_available_campaigns- how many there are, with the full list in thecampaignsattribute (useful in templates)sensor.tryber_latest_available_campaign- name of the first one in the list, with id, spots and deadline in the attributes
To list them all in a Markdown card:
{% for c in state_attr('sensor.tryber_available_campaigns', 'campaigns') %}
- **{{ c.name }}** ({{ c.free_spots }}/{{ c.total_spots }} spots)
{% endfor %}The integration also queries /users/me/campaigns with filterBy[accepted]=1,
which returns only the campaigns your application was accepted for, and
keeps those that haven't ended yet.
When a campaign id shows up there for the first time, the
tryber_campaign_selected event is fired on the bus with this data:
| Field | Content |
|---|---|
id |
Campaign id |
name |
Campaign name |
start_date / end_date |
Campaign dates |
close_date |
Application deadline |
campaign_type |
Campaign type (e.g. Functional, Experience) |
Like new campaigns, selections are persisted to disk and the very first startup only records the starting state without notifying anything.
automation:
- alias: "Tryber - selected for a campaign"
triggers:
- trigger: event
event_type: tryber_campaign_selected
actions:
- action: notify.mobile_app_iphone_16
data:
title: "You're in!"
message: >-
Selected for {{ trigger.event.data.name }}
{% if trigger.event.data.end_date %}
(until {{ trigger.event.data.end_date }})
{% endif %}
data:
url: "https://app.tryber.me/campaigns/{{ trigger.event.data.id }}"The full list of campaigns you're currently working on is in the campaigns
attribute of sensor.tryber_active_campaigns.
binary_sensor.tryber_bug_info_requested turns on when at least one bug you
reported is in the Need Review status, i.e. still open (neither approved
nor refused) and waiting for extra information from you.
Attributes:
count- how many bugs are in that statebugs- the list, each withid,title,campaign,campaign_idandseverity
{% for b in state_attr('binary_sensor.tryber_bug_info_requested', 'bugs') %}
- **{{ b.title }}** ({{ b.campaign }})
{% endfor %}- Home Assistant 2024.11 or later
- No additional Python dependencies
Pull requests and issues are welcome. The project is released under the MIT license: you can fork, modify and redistribute it, keeping the copyright notice.
Unofficial project, not affiliated with nor supported by AppQuality / Tryber.
It only uses user-area endpoints with your own personal credentials.
Mentioned trademarks belong to their respective owners.
The Tryber logo in custom_components/tryber/brand
is © AppQuality, used only to identify the integration in the Home Assistant UI;
it is not covered by this repository's MIT license.
MIT (c) 2026 Nicola Rodella