Skip to main content

Get started

Step 1 — Get TradingView Charting Library access

@iccandle/reactjs-widget requires TradingView Advanced Charts (Charting Library). Request access, install the library, and host it as static files by following TradingView’s Get started guide.

Serve the build from a path your app can load (e.g. public/charting_library/ in Vite or Create React App). The library is not bundled inside @iccandle/reactjs-widget; it loads at runtime via library_path on the widget options.

Step 2 — Install the package

npm install @iccandle/reactjs-widget
# or
pnpm add @iccandle/reactjs-widget

Ensure react and react-dom are installed and meet the peer version range (React 18+).

Step 3 — Bootstrap TradingView with replay helpers

Two helpers are required for chart replay / predict from the results iframe:

HelperWherePurpose
withPlayChartdatafeedWraps subscribeBars so the widget can inject replay bars and block live ticks during playback.
getCustomIndicatorscustom_indicators_getterRegisters the “Generated Candles” studies that draw predicted OHLC overlays.

Pass the same theme ("light" or "dark") to getCustomIndicators as your chart uses. See Configuration for signatures and study names.

import { useEffect, useRef, useState } from "react";
import type {
ChartingLibraryWidgetOptions,
IChartingLibraryWidget,
ResolutionString,
} from "charting_library/charting_library";
import { widget } from "charting_library/charting_library";
import { withPlayChart, getCustomIndicators } from "@iccandle/reactjs-widget";

const LIBRARY_PATH = "/charting_library/";

const containerRef = useRef<HTMLDivElement>(null);
const [chartWidget, setChartWidget] = useState<IChartingLibraryWidget | null>(
null,
);

useEffect(() => {
const el = containerRef.current;
if (!el) return;

const options: ChartingLibraryWidgetOptions = {
container: el,
library_path: LIBRARY_PATH,
symbol: "EURUSD",
interval: "60" as ResolutionString,
datafeed: withPlayChart(yourDatafeed),
locale: "en",
autosize: true,
drawings_access: {
type: "black",
tools: [{ name: "Date Range" }],
},
custom_indicators_getter: () => getCustomIndicators("light"),
};

const tv = new widget(options);
setChartWidget(tv);

return () => {
try {
tv.remove();
} catch {
/* no-op */
}
setChartWidget(null);
};
}, []);

You must supply a valid datafeed, symbol, interval, locale, and any other options required by your TradingView license and app. Import paths for widget and types differ by setup — follow TradingView’s docs for your bundler.

If your integration only exposes the instance after onChartReady, call setChartWidget inside that callback instead of immediately after new widget(...).

Step 4 — Wrap the chart with WidgetIccandle

WidgetIccandle wraps your chart and renders the scanner overlay plus the results iframe. Pass the live widget instance (or null while mounting):

import { WidgetIccandle } from "@iccandle/reactjs-widget";

<WidgetIccandle chartWidget={chartWidget} theme="light" language="en">
<div ref={containerRef} style={{ height: "100%", minHeight: 400 }} />
</WidgetIccandle>

Render prop for chart refs

Use a render-prop children when you need chartRefs for generated-candle studies (replay / predict):

<WidgetIccandle chartWidget={chartWidget} theme="dark" language="en">
{(chartRefs) => (
<ChartHost containerRef={containerRef} chartRefs={chartRefs} onReady={setChartWidget} />
)}
</WidgetIccandle>

A plain React node also works if you do not need those refs.

Step 5 — Enable Date Range drawing

The scanner selects a bar window with TradingView’s Date Range tool. Enable it in drawings_access:

drawings_access: {
type: "black",
tools: [{ name: "Date Range" }],
},

Default window size is 25 bars.

Auth

Users sign in through the embedded results app. On success, the embed posts sign-in-success and the parent stores iccandle_token in localStorage. Scan cache and pattern tracker APIs use that token as a Bearer credential.

You do not pass an API key prop to WidgetIccandle — auth is handled via the iframe login flow.

Theme and language

  • theme="light" / theme="dark" — forces that palette for scanner chrome and the iframe.
  • theme="system" — follows prefers-color-scheme.
  • language — one of en, zh, vi, th, ko, ja, mn, ru (defaults to en). Applied to scanner UI and the results iframe locale.

Full working example

import { useEffect, useRef, useState } from "react";
import type {
ChartingLibraryWidgetOptions,
IChartingLibraryWidget,
ResolutionString,
} from "charting_library/charting_library";
import { widget } from "charting_library/charting_library";
import {
WidgetIccandle,
withPlayChart,
getCustomIndicators,
} from "@iccandle/reactjs-widget";

const LIBRARY_PATH = "/charting_library/";

export function ChartWithIccandle() {
const containerRef = useRef<HTMLDivElement>(null);
const [chartWidget, setChartWidget] = useState<IChartingLibraryWidget | null>(
null,
);

return (
<div style={{ height: "100vh", width: "100%" }}>
<WidgetIccandle
chartWidget={chartWidget}
theme="light"
language="en"
onCloseResult={() => {
/* optional: react when the embed posts close-result */
}}
>
{(chartRefs) => (
<ChartHost
containerRef={containerRef}
chartRefs={chartRefs}
onReady={setChartWidget}
/>
)}
</WidgetIccandle>
</div>
);
}

function ChartHost({
containerRef,
chartRefs,
onReady,
}: {
containerRef: React.RefObject<HTMLDivElement | null>;
chartRefs: import("@iccandle/reactjs-widget").WidgetIccandleChartRefs;
onReady: (w: IChartingLibraryWidget | null) => void;
}) {
useEffect(() => {
const el = containerRef.current;
if (!el) return;

const options: ChartingLibraryWidgetOptions = {
container: el,
library_path: LIBRARY_PATH,
symbol: "EURUSD",
interval: "60" as ResolutionString,
datafeed: withPlayChart(yourDatafeed),
locale: "en",
autosize: true,
drawings_access: {
type: "black",
tools: [{ name: "Date Range" }],
},
custom_indicators_getter: () => getCustomIndicators("light"),
};

const tv = new widget(options);
onReady(tv);

return () => {
try {
tv.remove();
} catch {
/* no-op */
}
onReady(null);
};
}, [containerRef, chartRefs, onReady]);

return <div ref={containerRef} style={{ height: "100%", width: "100%" }} />;
}

Replace yourDatafeed and widget options with your real datafeed and TradingView settings.

Features overview

Pattern scanner

  • Subscribes to chart readiness, symbol, resolution, and drawing events.
  • Manages a date_range multipoint drawing for the bar window.
  • On scan: posts candles to the cache service, then navigates the results iframe with search parameters.
  • Optional advanced filters (symbols, top-k, lookback period, probability window) stored in localStorage under search-filter.

Results iframe

  • Loads https://embed-iccandle-app.iccandle.ai/{language}?theme=... by default.
  • After scan / news navigation, the src updates with search or similar-events paths.
  • On iframe load, the parent posts { type: "parent-origin", origin } so Stripe checkout can return to the host domain.

Pattern tracker

From the scanner popup, users can open a subscription modal to track a custom pattern (name + timeframes + symbols). Requires a valid iccandle_token.

News / economic events

  • Clicking a timescale mark can open an event info modal (currency calendar events; skips holidays / early / sentiment-only marks).
  • “Go to detail” loads similar events in the iframe and draws a vertical line on the chart.
  • Marks can be driven from localStorage keys tv:selected-news-events and tv:clicked-news-event if your datafeed implements getTimescaleMarks — see Optional: timescale marks.

Common patterns

PatternApproach
Full-page chart + resultsParent with height: 100vh; WidgetIccandle fills the viewport and lays out chart + iframe.
Theme syncPass theme from your app shell (light / dark / system).
Locale syncPass language to match your app locale.
Gate scans until iframe readyPass iframeLoaded={true} once the results iframe has loaded (or omit the prop if you do not gate).
News marks on the time axisImplement getTimescaleMarks and sync with localStorage — see Configuration.