Triggers
Automate Pitchfork actions based on account state, time, and group composition
Triggers are server-side rules that watch one or more accounts and run an action when a condition is met. Use them to stop bots when they hit a level target, swap accounts between groups when wealth crosses a threshold, alert you on bans, schedule batch launches, or kick off OAuth re-capture when sessions expire.
How they work
- Triggers are evaluated server-side, not on the agent. You can leave your machine and they still fire.
- Metadata triggers (level, skill, wealth, runtime, etc.) are checked on a polling loop — Pitchfork batches up to 100 accounts at a time every few minutes against accounts whose metadata recently changed.
- Event triggers (account banned, connection failed, status changed) fire as soon as the underlying event is recorded.
- Schedule triggers (
scheduled,one_time) fire from a separate polling service that respects timezones and cron expressions. - Every trigger has one or more actions. Multiple actions on a single trigger run in order; if one fails, the others still execute.
Trigger catalog
Account state
| Type | Watches | Common condition |
|---|---|---|
total_level_reached | Total skill level | threshold: 1500 |
quest_points_reached | QP count | threshold: 200 |
skill_level_reached | A specific skill | skill: "Mining", level: 70 |
wealth_reached | Bank + equipment value (gp) | threshold: 50000000 |
runtime_reached | Time since the bot started | minutes: 480 |
script_completed | Script reports completion | (no extra condition) |
account_banned | Account flagged as banned | (no extra condition) |
connection_failed | Connection to Jagex failed | failure_count: 3 |
account_status_changed | Status flipped | from: "running", to: "stopped" |
auth_capture_needed | Pitchfork detects expired session tokens | (no extra condition) |
Membership
| Type | Watches | Common condition |
|---|---|---|
membership_expired | Membership end date passed | (no extra condition) |
membership_expiring | Membership ends soon | days_remaining: 7 |
membership_status_changed | Member ↔ free flip | is_member: true |
Group composition
| Type | Watches | Common condition |
|---|---|---|
group_account_count | Total accounts in a group | threshold: 50 (operator chooses direction) |
group_running_low | Active-account count drops below floor | threshold: 10 |
group_continuous_launch | Idle accounts in a group, with cooldown | Filter by min_total_level, max_runtime_today, exclude_banned, require_member |
group_time_rotation | Accounts last touched too long ago | time_field: "last_closed_at", time_value: 2, time_unit: "hours" |
Schedule
| Type | Watches | Condition |
|---|---|---|
scheduled | Cron schedule | schedule: "0 4 * * *", timezone: "America/New_York" (4 AM daily Eastern) |
one_time | A specific instant | execute_at: "2026-06-01T08:00:00Z" |
Advanced conditions
Any trigger can use multiple_conditions to combine multiple field checks with AND/OR logic instead of a single threshold. Each condition has a field (e.g. total_wealth, combat_level, quest_points), an operator (>, <, >=, <=, ==, !=), and a value.
Action catalog
| Action | What it does | Key params |
|---|---|---|
stop_bot | Stops the running client | (none) |
pause_bot | Pauses without killing the client | (none) |
start_script | Launches a script | script_name, optional agent_id, optional profile |
start_account_tool | Queues an account tool | tool_type, optional parameters, priority, agent_id |
move_to_group | Reassigns account to another group | group_id |
randomize_group | Picks a random target group, optionally weighted | group_ids[], optional weights[] |
auth_capture | Triggers an OAuth grab | optional agent_id, optional proxy_group_id |
notify | In-app notification | message, level: "info" | "warning" | "error" |
webhook | POST or GET to an arbitrary URL | url, method, optional headers, custom_fields, include_account_data, include_trigger_data |
Worked example: stop and rotate when an account hits 99 Slayer
Create a skill_level_reached trigger with conditions skill: "Slayer", level: 99 and these actions, in order:
notify—message: "{{account.name}} hit 99 Slayer 🎉", level: "info"stop_botmove_to_group—group_id: <maxed_accounts_group_id>
Pitchfork picks up the metadata change within a few minutes of your script reporting it, fires all three actions, and your account ends up parked in the maxed-accounts group with a notification in your tray.
Worked example: keep a group running 24/7
Use a group_continuous_launch trigger on the group. Set:
cooldown_minutes: 30— don't relaunch the same account inside 30 min of stoppingexclude_banned: truerequire_member: truemax_runtime_today: 360— don't relaunch an account that's already botted 6 hours today
Action: start_script with the script and agent you want.
REST API
Triggers can be created and managed via the Public API under the /api/triggers resource. The shape mirrors the UI form: name, trigger_type, conditions, actions[], optional account_ids[] or account_groups[] to scope.
Caveats
- Polling latency. Metadata triggers can take up to a few minutes to fire after the underlying value changes. If you need real-time, use an event trigger or a webhook from your script.
- No cross-account conditions. A trigger evaluates one account at a time (group triggers being the exception). You can't write "fire when accounts A and B are both running" — use webhooks + your own logic for that.
- Action ordering matters when one mutates state another reads. Put
stop_botbeforemove_to_groupif your downstream logic cares about which group an account was in when it stopped.
Was this page helpful?