Skip to content

Trade Bridge

Lafko edited this page Jun 21, 2026 · 9 revisions

← Home


Trade Bridge (Browser Extension)

The Trade Bridge lets a browser extension do all trade-site work (live search, fetching, whispering) while POEFixer does only the in-game buying. This keeps the trade-site traffic inside your real browser session — no cookie copying, no cf_clearance hassle — and is the foundation for a future "run POEFixer on another PC" mode.

You can use the free official extension, or build your own against the documented protocol below.

The Trade Bridge requires your POEFixer license to have the Trade feature. If Trade is configured as paid on the server, you need a valid key; if it is free, anyone can use it. When not entitled, the bridge replies entitlement_required and refuses buys.


1. How it works

Browser extension                         POEFixer
  live-search WebSocket  ─┐
  fetch item details      │  ws://127.0.0.1:PORT   in-game buying:
  whisper (teleport)      ├─────────────────────►  wait teleport → click → verify
  (Force teleport,        │   buy_request           → auto-stash → /hideout
   In-demand retry,       │ ◄─────────────────────  → report result
   Rate limiting)        ─┘   buy_result
  • The extension owns everything that touches the trade site.
  • POEFixer owns everything in the game client, and exposes a local WebSocket server (the Trade Bridge) that the extension connects to.
  • In this mode POEFixer's built-in tls-client is not used, and the trade-site controls (Connections, Trade Cookies, Force teleport, In-demand, Rate limiting) move into the extension and are hidden/disabled in POEFixer.

2. Install the extension

First, in POEFixer: Configuration → Trade → Trade data source → Browser extension. Note the Port (default 47362) and click Start bridge on the Trade tab's Extension Link panel.

A fully silent one-click install is not possible — browsers block programmatic extension installs by design. POEFixer's Assisted install… button does the parts it can (stages the extension folder, copies its path to the clipboard, opens this guide); you finish the last 2–3 clicks in the browser.

Chrome / Edge

  1. Open chrome://extensions (Edge: edge://extensions).
  2. Enable Developer mode (top-right).
  3. Click Load unpacked and select the extension folder (the path the Assisted-install button copied, or extension/dist/chrome).
  4. The extension icon appears in the toolbar. It stays loaded across restarts.

Firefox

Release Firefox only installs Mozilla-signed extensions.

  • Testing: open about:debugging#/runtime/this-firefoxLoad Temporary Add-on → pick extension/dist/firefox/manifest.json (removed on restart).
  • Persistent: install the signed .xpi (AMO self-distributed) by opening it in Firefox and confirming the permission prompt.

Advanced (not recommended)

Enterprise-policy force-install (ExtensionInstallForcelist / ExtensionSettings) can auto-install from a hosted package, but it shows "managed by your organization", needs admin rights, still requires store hosting/signing, and may trip antivirus. Use only if you know what you're doing.


3. Use it

Everything is controlled from POEFixer — the extension popup only sets the connection Port.

  1. In POEFixer: Configuration → Trade → Data source = Browser extension, set the Port, click Start bridge.
  2. In the extension popup, confirm Host: connected and the same Port.
  3. Log in to the trade site in the same browser.
  4. In POEFixer's Trade Links (Connections tab) add your trade2 search URLs and press Play — the search is pushed to the extension and runs there; Stop removes it.
  5. Set behavior in POEFixer (Configuration → Trade): Force teleport, Item is in demand → teleport anyway, Rate limiting — POEFixer pushes these to the extension, which just obeys.
  6. When a listing matches, the extension whispers and POEFixer buys in-game. All extension activity appears in POEFixer's Logs (category Trade).

Reliable live feed (automatic): for each active search the extension opens a pinned background tab to the trade page and connects the live WebSocket inside that page (correct Origin + your session cookies — exactly like the site does). Just stay logged in to the trade site; you don't open Live Search manually. The Trade Link shows Connecting… until the live WS is up, then Live. Closing that pinned tab stops the search.


4. Build your own extension — Trade Bridge API (PTBP)

The protocol is plain JSON over a WebSocket. Anyone can implement it. POEFixer hosts the server; your client connects to ws://127.0.0.1:<port> (default 47362, configurable in Settings).

The host honors buys only when your license has the Trade entitlement. Otherwise you receive {"type":"error","code":"entitlement_required"}. (Authentication details are intentionally not documented.)

4.1 Handshake

Send hello first; the host replies welcome.

// client → host
{ "type":"hello", "proto":1, "client":"MyExtension/1.0", "token":"<optional>" }
// host → client
{ "type":"welcome", "proto":1, "host":"POEFixer", "allowed":true, "paid":false, "ready":false }
  • allowed:false → not entitled (treat as "buy a key"); the host will reject buys with entitlement_required.
  • token is only needed if the user enabled a pairing token in POEFixer (off by default).

After welcome (and whenever the user changes anything in POEFixer), the host pushes a config message. The program is the single control surface, so your extension must monitor exactly these searches and obey this behavior:

// host → client
{ "type":"config",
  "behavior":{ "forceTeleport":false, "inDemandRetry":true, "rateLimit":true },
  "searches":[ { "realm":"poe2", "league":"Standard", "searchId":"", "note":"" } ] }

4.2 Readiness — whisper only when ready

The host pushes status periodically:

{ "type":"status", "ready":true, "inGame":true, "attached":true, "busy":false }

You MUST only whisper/teleport when the last status.ready === true. ready = entitled && attached && in-game && !busy. Whispering while not ready teleports the character with no buyer driving the trade.

4.3 Buy flow

After your whisper succeeds (the character is teleporting), send buy_request:

// client → host
{ "type":"buy_request", "id":"r-42", "seq":7,
  "group":{
    "groupId":"g-9", "isLastGroup":true,
    "items":[ {
      "itemId":"...", "stashX":3, "stashY":1, "w":1, "h":1,
      "price":{ "currency":"chaos", "amount":50 },
      "seller":"AccountName", "stashName":"~price 50 chaos",
      "name":"...", "typeLine":"...", "baseType":"...", "rarity":"Rare",
      "iconUrl":"https://...", "ilvl":82, "corrupted":false, "identified":true,
      "explicitMods":[ "..." ], "implicitMods":[ "..." ],
      "league":"Standard", "realm":"poe2",
      "hideoutToken":"...", "indexedTime":"..."
    } ] } }

The host acks it, optionally emits progress, then a single result:

{ "type":"ack", "ackSeq":7 }
{ "type":"buy_progress", "id":"r-42", "phase":"teleporting" }
{ "type":"buy_result", "id":"r-42", "seq":11,
  "items":[ { "itemId":"...", "ok":true, "reason":"verified" } ],
  "summary":{ "bought":1, "failed":0 } }
  • stashX/stashY are the item's coordinates in the seller's shop; w/h its size — these drive the in-game click.
  • hideoutToken is carried for logging only (you already used it to whisper).
  • You must ack each buy_result: send {"type":"ack","ackSeq":<buy_result.seq>}.

4.4 Whisper-stage events + logs (ext → host)

Whisper-stage outcomes (keep POEFixer's logs complete):

{ "type":"trade_event", "seq":8, "stage":"whisper", "outcome":"in_demand", "itemId":"...", "detail":"" }
// outcome ∈ in_demand | whisper_failed | fetch_error

Forward your activity to POEFixer's log (recommended — all extension logs should surface in the program):

{ "type":"log", "level":"info", "message":"" }   // shown in POEFixer Logs (category Trade)

Report each search's live-WS state so POEFixer's Trade Link shows Connecting…/Live:

{ "type":"search_status", "searchId":"", "state":"connected" }   // state ∈ connected | closed | error

4.5 Reliability

  • buy_request and trade_event carry an incrementing seq; the host acks them. Keep un-acked frames and resend them on reconnect (sorted by seq).
  • buy_request.id is the idempotency key — a re-sent id returns the recorded buy_result (or error: duplicate while still in flight). Use a stable, unique id per buy.
  • buy_result carries a seq that you ack.

4.6 Errors

{ "type":"error", "code":"entitlement_required|not_in_game|busy|duplicate|bad_request|unauthorized|proto_unsupported", "id":"r-42", "detail":"..." }

4.7 Minimal client (JavaScript)

const ws = new WebSocket("ws://127.0.0.1:47362");
let ready = false, seq = 0, behavior = {}, searches = [];
const log = (message) => ws.send(JSON.stringify({ type:"log", level:"info", message }));
ws.onopen = () => ws.send(JSON.stringify({ type:"hello", proto:1, client:"MyExt/1.0" }));
ws.onmessage = (e) => {
  const m = JSON.parse(e.data);
  if (m.type === "welcome" && !m.allowed) console.warn("Trade entitlement required");
  if (m.type === "config") { behavior = m.behavior; searches = m.searches; } // program controls you
  if (m.type === "status")  ready = m.ready;
  if (m.type === "buy_result") ws.send(JSON.stringify({ type:"ack", ackSeq:m.seq }));
};
// monitor `searches`, obey `behavior`; after YOUR whisper succeeds and ready === true:
function buy(items) {
  ws.send(JSON.stringify({ type:"buy_request", id:"r-"+Date.now(), seq:++seq,
    group:{ groupId:"g", isLastGroup:true, items } }));
}

5. Troubleshooting

  • Host: disconnected — POEFixer not running, bridge not started, or wrong port. Start the bridge in Settings → Trade; match the port in the popup.
  • entitlement_required — your license lacks the Trade feature (paid on the server).
  • not_in_game — POEFixer isn't attached/in-game; wait for status.ready.
  • Live search never fires — the trade live WebSocket may reject the extension's origin; keep a trade2 search tab open so the content-script fallback can ride the page's own connection.
  • Port in use — change the port in Settings → Trade and in the popup, then restart the bridge.

← Home

Clone this wiki locally