Stockbit realtime (opt-in)
idx reads IDX data from free, keyless public endpoints. Stockbit is the one
exception: an opt-in provider that serves realtime quotes, history and a live
order book from Stockbit's own backend, carrying your
own Stockbit account session. It is never in the provider auto chain:
quotes and history use it only when you ask for it with --provider stockbit.
The same session also reads what only Stockbit has in one place: every corporate
action of a stock since its listing, the market's corporate-action calendar, and
the insider and 5 % holder movements filed with IDX and KSEI (idx stockbit actions, idx stockbit calendar, idx stockbit movements). And idx broker
lists every broker that bought and sold a stock from it, by itself once you are
logged in (see Broker summary).
This uses an unofficial, undocumented API with your personal account. It may conflict with Stockbit's Terms of Use, and automated access could get an account flagged. Use your own account, at your own risk, at a human-ish request rate.
idxis not affiliated with or endorsed by Stockbit.
Log in once
idx stockbit login
idx never asks for your Stockbit password. You sign in on stockbit.com itself,
and idx takes only what that sign-in leaves behind: the credentialStorage
cookie, which holds the session's two tokens. Whichever way it arrives, idx
first stores it (0600), then checks it with one request to Stockbit; when
Stockbit refuses it, the previous session is put back (or none, if there was
none) and nothing changes. When the session already stored still works and
idx can renew it, login says so and stops; --force signs in anyway.
In a browser idx opens (the default on a desktop): idx launches a
Chromium-family browser (Chrome, Edge, Brave; --browser or IDX_BROWSER
chooses one) on Stockbit's sign-in page, with a profile only idx uses
(stockbit-chrome-profile beside the session file; --profile moves it). You
sign in there, with whatever Stockbit asks (password, OTP, captcha). idx reads
nothing but cookies over the Chrome DevTools Protocol: it intercepts no request,
so the password never passes through idx. Once Stockbit accepts the session,
idx closes Stockbit's tab, deletes the cookie from its profile (so a later run
cannot pick up a pair idx has since rotated) and closes the browser. The
profile keeps Stockbit's other cookies, so the next sign-in may skip a step.
Google sign-in refuses browsers driven this way ("This browser or app may not
be secure"); use the local page instead.
Through a local page (--page; also chosen by itself over SSH, without a
display, or without a Chromium-family browser):
idx stockbit login --page # prints http://127.0.0.1:7878/login/<secret>
idx stockbit login --page --port 7878 # pin the port, e.g. for an SSH forward
idx serves a page on 127.0.0.1 only, at a path with a random secret, for the
browser you already use (any browser, Firefox included). Over SSH it also prints
the forward to run on the machine with the browser, for example
ssh -N -L 7878:127.0.0.1:7878 you@server; then open the URL there. On the
page:
- Open a private window and sign in at stockbit.com (Google sign-in works here). idx then holds a session of its own while your everyday browser keeps its own.
- Drag Send to idx to the bookmarks bar, then click that bookmark on the
stockbit.com tab. It runs only on stockbit.com, reads
credentialStoragethere and opens the page with the value in the address fragment, which the browser never sends to any server. A bookmark from an earlier run carries an old secret: drag it again. - Or paste the cookie into the page (DevTools > Application > Cookies, or the clipboard button).
The page posts only that value to idx, which checks it with Stockbit and
answers on the page. Close the private window afterwards without signing
out. The page answers only on its secret path, only to a loopback Host, and
takes a POST only from a loopback origin; it keeps no copy, sets no-store,
no-referrer and a CSP that allows nothing outside the page, accepts one
session and stops (or after --timeout, 300 seconds by default). Port 7878 is
the default; when it is taken idx picks a free one, --port pins it and
--port 0 takes any.
By pasting the cookie, from any browser:
idx stockbit login --manual # paste it into this terminal
pbpaste | ssh you@host idx stockbit login # or pipe it; a pipe on stdin means paste
Sign in at stockbit.com (a private window keeps your everyday browser's session
apart, see One refresher per session), open DevTools (F12) > Application >
Cookies > https://stockbit.com and copy the value of credentialStorage. A
bare refresh token works too. Close that window afterwards without signing out:
signing out there may end the session idx now holds.
The session is stored locally (see Where the session lives) and refreshed for you from then on. Check it any time:
idx stockbit status # logged in? when do the tokens expire?
idx stockbit logout # delete the stored session
status reads the stored tokens' own expiry and sends nothing. The access
token lasts about a day and the refresh token about a week. idx refreshes
only when a request needs it (the access token has expired, expires within the
hour, or Stockbit refused it), and each refresh replaces both tokens, so a
request made while the access token is still good renews nothing. The refresh
token therefore runs out about a week after the last refresh, which can be up
to a day short of a week after the last use; using idx at least every six days
keeps the session working. Once the refresh token has run out too, status
says logged in no, with a note that the session expired and that
idx stockbit login renews it ("logged_in": false, "expired": true in JSON).
While only the access token can still be used (its refresh token expired, or
none is stored), logged in is yes with a note that the session stops working
when that token expires ("renewable": false). A session Stockbit ended early
(signed out elsewhere, or refreshed by another tool) still reads as logged in
until a request finds out: that request fails naming idx stockbit login, and
the process that sent it (a running idx mcp server, say) then reports that
Stockbit refused the refresh token; idx stockbit status, a process of its
own, cannot tell.
Use it
Once logged in, point any quote/history command at the provider:
idx --provider stockbit stocks quote BBCA BBRI # realtime, not delayed
idx --provider stockbit stocks history BBCA --period 1mo
idx --provider stockbit stocks intraday BBCA # today's one-minute bars, realtime
idx config set provider stockbit # make it the default
idx config set history_provider stockbit # or: candles only, free providers for the rest
history_provider (--history-provider, IDX_HISTORY_PROVIDER) picks where
candles come from apart from provider. With history_provider = "stockbit"
the free providers keep serving quotes, fundamentals, financials and the rest
while history, technicals, returns and the brief take Stockbit's candles. Under
provider = "stockbit" the default history_provider = "auto" keeps on
Stockbit only the requests whose bars Stockbit returns as asked (daily over
1mo to 1y, hourly over 5d, weekly over 5y, same-day intraday) and sends
the rest (2y or 5y daily, 1y weekly, any monthly bars) to Yahoo with a
note; when
the session fails it falls back to Yahoo with a warning. history_provider = "stockbit" keeps every window on Stockbit. See
configuration.md.
And read the live order book (Stockbit-only — the free sources have no depth):
idx stockbit orderbook BBCA # depth ladder + session foreign flow
idx stockbit orderbook BBRI --depth 5
idx -o json stockbit orderbook TLKM | jq '.data.bids[0]'
Sizes in the order book are shares (one IDX lot is 100 shares); values are
IDR. History candle volumes are converted from Stockbit's lots to shares so they
match the other providers. Stockbit chooses the candle granularity and span from
the window (1d is one-minute; 5d, and intraday intervals over any longer
period, hourly over one week; 1mo to 1y daily; 2y weekly over three years;
5y and longer weekly over five years), and a warning says so whenever those
bars are not the --interval asked for or that span is not the --period
(--period 1y --interval 1wk gets daily bars and a warning; --period 1mo --interval 1h gets one week of hourly bars and a warning, since the candles
are not trimmed to the period; --period 5d --interval 1h gets the hourly bars
it asked for and none).
Foreign flow in the order book (foreign_buy, foreign_sell, foreign_net)
comes with a flag, has_foreign_bs. While it is false the figures are not the
current session's: a BBCA book recorded in session 2 on 2026-11-03 carried a
foreign net of -116.1B, which is IPOT's figure for 2026-11-02 (2026-11-03 itself
closed at -28.8B). So idx keeps the three figures only while Stockbit marks them
current (true, as in idx's own books recorded after the close) and otherwise
leaves them empty, with a warning that says why (on stderr in a table, in
warnings in JSON). A missing or non-boolean flag counts as not current. The
false book came from another account (recorded by 0xrsydn/idx-cli), and its
orderbook_active_feature_mobile differs too (ORDER_BOOK_FEATURE_UNSPECIFIED,
where idx's books say ORDER_BOOK_FEATURE_FOREIGN_BS), so it is still open
whether the flag follows the session clock or an account feature. idx reads only
the flag, so either way the figures show only when Stockbit marks them current.
stocks intraday takes its bars where candles come from, so with
--provider stockbit or history_provider = "stockbit" it shows today's
realtime one-minute bars from your session during trading hours; the default
providers serve Yahoo's delayed bars without a login. When the day's window is
still empty, idx retries over five days only with a source whose five-day
window has the bars asked for: under --provider stockbit that is Yahoo (the
last session's bars, with a warning naming its date), while with
history_provider = "stockbit" there are no bars until Stockbit has some
(Stockbit's five-day window is hourly; the quote still answers).
The Stockbit provider covers quote, history and orderbook. The other
commands (fundamentals, financials, news, …) stay on the free providers; run
them without --provider stockbit, or keep provider on auto and set only
history_provider = "stockbit".
Corporate actions and calendar
idx stockbit actions BBCA # every kind but ipo, newest first
idx stockbit actions TLKM --kind dividend
idx stockbit actions BBRI --kind split,bonus,rights --from 2015-01-01
idx stockbit calendar # the next 14 days, oldest first
idx stockbit calendar --kind dividend --days 30
idx stockbit calendar --kind ipo,tender --from 2026-01-01 --to 2026-12-31
One structured row per action, with the dates and terms and no announcement
text (schema idx.stockbit.actions.v1). Kinds: dividend, stock_dividend,
bonus, rights, warrant, split, reverse_split, rups (alias
meeting), public_expose (expose), ipo, tender_offer (tender), or
all. Each kind is one request, a second apart, cached for 6 hours; a kind that
fails leaves a warning and the others still show. The pause holds across every
command and MCP tool call on the same session in one idx process, so parallel
tool calls queue a second apart too.
- A row's
dateis its cum date for dividends, bonuses, rights and splits (the ex date when there is none), else the event's first day: a warrant's first trading day, the meeting or expose day, an IPO's listing day, a tender offer's opening day. stockbit actionsreads a stock's whole history: BBCA's cash dividends go back to 2009, its splits to 2004.--from/--tonarrow it. The default is every kind butipo.stockbit calendarreads the market-wide lists and keeps the rows dated in the range (at most 366 days; default today and the next 14), plus rights trading windows, tender offers and IPO offerings still open in it. The default is every kind butwarrant: most market-wide warrant rows are structured warrants, listed under their own codes (ASIIZPCN7A), dozens a month.- As recorded on 2026-11-03, the market-wide lists reach about a year back and as far ahead as announced, except RUPS and public exposes, whose market lists started on the recording day. The stock dividend and reverse split lists were empty that day; their rows are read by the field names the other entitlement rows use.
ratio_old : ratio_newis as published (1 : 5 for a five-for-one split, 655 held : 104 rights).priceis the rights or warrant exercise price, the tender offer price, or the final IPO price, IDR per share. Anything Stockbit leaves empty or zero isnull.
Without a login, idx stocks actions (IPOT, with the announcement texts) and
idx market calendar (the exchange's own calendar) cover similar ground.
Insider and 5 % holder movements
idx stockbit movements BBCA # one stock, newest first
idx stockbit movements # the whole market
idx stockbit movements --source ksei --action sell
idx stockbit movements --from 2026-10-01 --to 2026-10-31 --pages 5
idx stockbit movements --holder 1000004481 # one holder, by the HOLDER ID column
Reported changes in a holder's stake (schema idx.stockbit.movements.v1), from
two kinds of filing that Stockbit shows in one feed:
idx: insider disclosures to IDX. Directors, commissioners and other insiders, any size, with the trade price the insider filed.ksei: KSEI's daily changes of holders at 5 % and above. No price is filed; Stockbit shows an estimate, which idx keeps inestimated_priceandestimated_value(shown as~21in the table), never inpriceorvalue.
shares_from, shares_to and shares_change are exact and signed;
pct_from, pct_to and pct_change are percent of the company as Stockbit
rounds them (an insider's 0.0003 % stays 0.0003). A rights issue the holder did
not take up shows as shares_change: 0 with a negative pct_change. --action
filters buy, sell, transfer, cross (crossings between accounts: repos,
pledges) or corporate-action (rights issues, private placements, tender
offers and the like); each row's own action is Stockbit's label, lowercased.
--holder takes the digits of a row's holder_id, the same on every row of
that holder.
Stockbit serves 50 rows a page; --pages reads up to 10, one request each, a
second apart, cached for an hour. more says rows remain. The feed gains rows
at the top as filings arrive, so a row repeated across pages is kept once, a
page cached before the page above it was read is read again live (rows that
moved down past the page break would otherwise be on neither page; when it
cannot be read again, a warning says rows may be missing), and a later page
that fails keeps the rows already read (with a warning).
These are filings, not signals: a share plan reads as many insiders buying at
one price on one day (BBCA's directors on 2026-03-25 at 6,982), crossings name
securities firms as holders, and rows appear days after the change. The
monthly register of holders above 1 % (idx ownership, no login) is the other
view.
Broker summary
idx broker BBCA # every broker, once logged in
idx broker BBCA --source stockbit -n 0 # Stockbit or nothing, every row in the table
idx broker BBRI --from 2026-11-02 --to 2026-11-06 --investor foreign
idx broker BBCA --source ipot # IPOT's top 10, no login
idx broker reads Stockbit's broker summary by itself once a working session is
stored (what idx stockbit status calls logged in): --source auto, the
default, takes Stockbit then and IPOT otherwise, and --source stockbit fails,
naming idx stockbit login, when no session works. The schema stays IPOT's,
idx.broker.v1:
- idx asks for gross figures: each broker's own buying on the buy side and its own selling on the sell side, as IPOT publishes them. Stockbit's net mode lists each broker once, on the side where it was net; idx does not use it and refuses a reply in those figures.
- Every broker is listed. BBCA had 59 buyers and 67 sellers on 2026-11-06, and
92 a side over the year to that day.
buyer_countandseller_countare Stockbit's counts;buyers_completeandsellers_completesay whether each list holds them all. A cut list keeps its totalsnull, and the table saysTop buyers (5 of 59). - Stockbit ranks a side by value; idx orders it by lots, as IPOT ranks, so
rankmeans the same. Ordered so, Stockbit's first ten were IPOT's top 10 for 2026-11-06 and for 2026-11-02 to 2026-11-06: the same brokers in the same order, with the same lots and values at IPOT's precision. Classes are Stockbit's own labels (Asing,Lokal,Pemerintah), which can differ from IPOT's: HD is foreign on Stockbit and local on IPOT. - Figures are exact (
rounded: false), and odd lots count as fractions of a lot (YU bought 108,898.5 lots that day). Totals are sums over the full lists: both sides came to 1,035,652,066,452 IDR. Stockbit's own totals are the buy side's at about eight significant digits and are not used. - The foreign net comes from a second read, of foreign investors over the same
range and board: their buying less their selling, 218,988,301,100 IDR for
BBCA on 2026-11-06 (IPOT's
F. NVal: 219.0 B). With--board regularit is the regular board's, which IPOT does not publish. A day without trades needs no second read; when the second read fails the net isnullwith a warning. - A range is one read, aggregated by Stockbit, so no session is rebuilt one by one as IPOT's foreign net over a range is.
- Domestic investors and the cash and negotiated boards have not been recorded
yet, so idx does not ask Stockbit for them:
autotakes IPOT, with a note, and--source stockbitis a usage error. - Under
auto, a ticker Stockbit fails for (its CDN refusing this network, a session Stockbit ended) is read from IPOT with a warning; after a failure no other read could get past, the rest of the call is read from IPOT too. Each summary'ssourcesays which answered. - Reads are paced a second apart like the other Stockbit lists: one or two per ticker, plus one per weekday without trades while looking for the latest session. A range that ended before today is cached for a week, one that reaches today for five minutes.
Without a working session, or with --source ipot, the summary is IPOT's top 10
as before; under auto a note then says a login lists every broker, when a list
reached IPOT's ten rows.
MCP
The MCP server exposes five Stockbit tools alongside the rest:
idx_stockbit_status: can the stored session work now (logged_in;expired,renewableandreasonsay why not, or why idx cannot renew it), and when do the tokens expire (never the token values). Call it before the others.idx_orderbook: the live depth ladder and foreign flow for one ticker.idx_stockbit_actions: one stock's corporate actions (symbol), or the market calendar without one;kind,from,to,daysas on the CLI.idx_stockbit_movements: insider and 5 % holder movements;symbol,from,to,holder,action,source,pagesas on the CLI.idx_stockbit_login: starts a sign-in.method: pagereturns at once with a URL on 127.0.0.1 (and thessh -N -Lforward when the server is reached over SSH) for the user to open in their own browser, as with--page; the agent then pollsidx_stockbit_status, whosesign_inshowswaiting,signed_inorfailed.method: browseropens a browser on the machine running the server and waits, which only suits a local stdio server the user sits at. A session that already works, and that idx can renew, is reported without opening anything (forcesigns in anyway). The tool never asks for, and agents should never ask the user for, a password, a cookie or a token in the chat. Prefer telling the user to runidx stockbit loginin a terminal themselves.
idx_broker reads the same session: its source (auto, ipot,
stockbit) works as --source does on the CLI, so an agent gets every broker
once the user is logged in.
To serve realtime quotes/history over MCP, run the server with the Stockbit
provider: idx --provider stockbit mcp. For Stockbit candles with the free
providers for everything else, register it with
-e IDX_HISTORY_PROVIDER=stockbit instead.
Where the session lives
The session file holds the rotating tokens and is written with 0600
permissions on Unix. By default it sits beside the default config file (e.g.
%APPDATA%\idx\stockbit-session.json on Windows,
~/.config/idx/stockbit-session.json on Linux), also when --config points
elsewhere. Move it with:
stockbit.sessioninconfig.toml;IDX_STOCKBIT_SESSION=/path/to/session.json.
For an unattended deployment (a server, the web worker) seed the tokens through the environment instead of logging in interactively:
IDX_STOCKBIT_REFRESH_TOKEN— the refresh token (required);IDX_STOCKBIT_ACCESS_TOKEN— an access token to start with (optional).
The file always wins over the env seeds; the seeds only fill an empty session.
One refresher per session
Stockbit's POST /login/refresh rotates the refresh token: every refresh
mints a new one and retires the token it was given. So a single session must
have exactly one process refreshing it. If you point two tools (say idx and
another bot) at the same Stockbit session, they will retire each other's token
and both get logged out. Give each its own idx stockbit login / account, or
let one own the refresh and feed the other its current token.
Inside idx, refreshes are serialised so that one session does have one
refresher: a process keeps one session store per session file (the CLI
handler, the --provider stockbit provider, every MCP tool call and every
MCP HTTP session share it; an MCP server takes it once when it starts and
holds it until it stops), and a refresh also takes a lock file beside the
session (stockbit-session.lock) so a CLI command and a running MCP server do
not refresh at the same moment. Inside both locks the file is read again: a
pair another holder just stored is used, not refreshed a second time. A lock
older than a minute counts as left behind by a crashed process and is taken
over. A refresh token Stockbit refuses is not presented again by the same
process; idx stockbit login is the way back.
What idx talks to
All on https://exodus.stockbit.com, with Authorization: Bearer <access JWT>
and browser-shaped origin/referer headers:
| endpoint | used for |
|---|---|
GET /company-price-feed/v2/orderbook/companies/{SYM} | quote (OHLC, volume, value, foreign flow only while has_foreign_bs is true) and the full depth ladder |
GET /charts/{SYM}/daily?timeframe=..&chart_type=PRICE_CHART_TYPE_CANDLE | OHLCV candles |
GET /corpaction/{type}[?symbol={SYM}] | corporate actions, one kind per request: dividend, stock_dividend, bonus, rightissue, warrant, stocksplit, reversesplit, rups, pubex, ipo, tenderoffer |
GET /insider/company/majorholder?page=N[&symbol=][&date_start=][&date_end=][&insider=][&action_type=][&source_type=] | insider and 5 % holder movements, 50 rows a page |
GET /marketdetectors/{SYM}?transaction_type=TRANSACTION_TYPE_GROSS&market_board=MARKET_BOARD_ALL|_REGULER&investor_type=INVESTOR_TYPE_ALL|_FOREIGN&from=..&to=..&limit=1000 | the broker summary: every broker that bought and sold over the range (idx broker) |
GET /company-price-feed/market-time/session | checks a session before idx stockbit login stores it (never from the cache) |
POST /login/refresh | rotate the session (bearer = refresh token, empty body) |
The same API places orders and moves cash, so idx keeps an allowlist of the
read-only paths above and refuses any other URL before a token is read. A 401,
or a 403 with a JSON body, means Stockbit refused the access token: idx
refreshes once and retries once. A 403 with an HTML body is Stockbit's CDN
(CloudFront) refusing this client or network; a refresh cannot change that,
so idx reports it and does not retry. The same goes for POST /login/refresh:
only a 401, or a 403 with a JSON body, counts as a refused refresh token there;
an HTML 403 is reported as the block, and the token stays usable once it lifts.
Indices use Stockbit's own code (IHSG, LQ45), mapped from idx's caret form
(^JKSE, ^JKLQ45). The token is never written to a log, an error message or a
cache key.