# Lumen Charts documentation

Public integration documentation for a proprietary library. Runtime access is separately authorized. Exported API signatures do not imply that all legacy capabilities are supported; preserve compatibility notes when using these documents.

<!-- Public documentation export; not library implementation source. -->
# Installation and asset hosting

Lumen Charts is proprietary software. This site gives you technical documentation and an interactive demo to try it out. It is not a public library download or source repository, and there is no public npm install command. Two parts are the exception: the [AI integration SDK](https://docs.lumencharts.com/charting-library/automation/) and the [trading platform](https://docs.lumencharts.com/charting-library/trading/) are open source under the Apache License 2.0 and install from npm.

## Runtime access

To use the chart in production you need [a licence](https://lumencharts.com/pricing), which gives you the runtime and its matching TypeScript declarations as a download from your account. The runtime is a minified production build without source maps; the declarations describe the whole public API. It makes no network calls of its own and needs no licence key. Source code is not part of a standard licence; ask us about Enterprise if you need it.

You can try the chart in the [interactive demo](https://docs.lumencharts.com/demo/) without installing anything. The demo loads compiled browser files so it can run in your browser. That doesn't give permission to reuse or redistribute them.

The hosting steps below apply once you have an authorized copy. Serve the files over HTTP; opening the page as a `file:` URL won't work.

## Directory layout

```text
index.html
your-datafeed.js
lumen_charting_library/
  lumen_charting_library.js
  lumen_charting_library.inner.js
  lumen_charting_library.inner.css
  assets/
    chart-automation.js           # automation runtime, loaded by openAutomation()
    chart-trading.js              # trading runtime, loaded by loadTrading()
    chart-trading.css
  bundles/                       # optional Pine assets
  lumen_charting_library.d.ts
  datafeed-api.d.ts
```

Set `library_path` to the runtime folder, including the trailing slash. The script URL and `library_path` must point to the same release. Serve JavaScript and CSS with the correct MIME types, and return a real 404 for missing files. If your server returns an HTML page in place of a missing script, the chart will fail to start.

## Automation runtime

Every release includes `assets/chart-automation.js`. Host it with the other files and keep it from the same build as the core. The chart downloads it only on the first `openAutomation()` or `widget.loadAutomation()` call, so charts that never use automation never load it. The SDK that drives it is open source and installs from npm; shipping the runtime file doesn't import the SDK or configure an AI provider. See [AI integration](https://docs.lumencharts.com/charting-library/automation/) for the product boundaries and SDK setup.

## Trading runtime

Every release also includes `assets/chart-trading.js` and `assets/chart-trading.css`. Host them with the other files, from the same build as the core. The chart downloads them only when you call `widget.loadTrading()`, so charts without trading never load them. See [Trading](https://docs.lumencharts.com/charting-library/trading/) to connect a broker.

## Base paths and caching

If your app lives under `/terminal/`, use `/terminal/lumen_charting_library/` or another path that resolves to the same place. Putting the version in the path lets you cache files forever without mixing an old wrapper with new inner files. Deploy all the files together in one step, and keep the previous release around so you can roll back.

To start, serve the runtime files from the same origin as your app. Moving them to a CDN means also handling iframe access, CSS, worker loading and CSP. Moving images to another host is fine, but that doesn't mean the runtime scripts can move safely too.

## Content security policy

Right now the startup script writes the iframe document and uses inline startup configuration. Test your app's script, frame and style policies against the actual release rather than copying a strict generic policy. Optional Pine also needs permission to run a worker. If something is blocked, don't turn off CSP entirely. Find the blocked resource in the browser console and allow only what it needs.

[Show your first chart →](https://docs.lumencharts.com/charting-library/getting-started/quickstart)

---
Documentation page: https://docs.lumencharts.com/charting-library/getting-started/installation


---

<!-- Public documentation export; not library implementation source. -->
# Your first chart

You'll need an [authorized copy of the runtime](https://docs.lumencharts.com/charting-library/getting-started/installation) and a datafeed. Just want to see it work? The interactive example at the bottom of this page uses sample data and needs no install.

## Create a container

Give the chart container a real height. `autosize` makes the chart fill its container, but it can't give an empty container a height.

```html
<div id="chart" style="width:100%;height:560px"></div>
<script src="./lumen_charting_library/lumen_charting_library.js"></script>
```

## Mount the widget

```js
import { createDatafeed } from './your-datafeed.js';

const feed = createDatafeed();
const widget = new LumenChartingLibrary.widget({
  container: 'chart',
  library_path: './lumen_charting_library/',
  datafeed: feed.datafeed,
  symbol: 'AAPL',
  interval: '1D',
  locale: 'en',
  timezone: 'Etc/UTC',
  autosize: true,
  theme: 'light',
});

widget.onChartReady(() => {
  console.log(widget.activeChart().symbol());
});

// When the view is destroyed:
// widget.remove();
// feed.dispose();
```

## TypeScript

Import types from the declaration files that ship next to your runtime. The script tag above loads the browser global. A type-only import gives you types but doesn't load the runtime.

```ts
import type { LumenChartingLibraryWidgetOptions, ResolutionString } from './lumen_charting_library/lumen_charting_library';
const options: LumenChartingLibraryWidgetOptions = {
  container: 'chart', library_path: './lumen_charting_library/',
  datafeed, symbol: 'AAPL', interval: '1D' as ResolutionString, locale: 'en',
};
```

Here `datafeed` is your own datafeed. The library doesn't come with a market data connection. In TypeScript, resolutions use the `ResolutionString` type. Decide which values you support and check them in your datafeed.

## Check that it works

You should see candles and volume, a symbol toolbar and drawing controls. If the container stays blank, the usual causes are a missing runtime file, a parent with zero height, or a datafeed callback that never gets called. See [troubleshooting](https://docs.lumencharts.com/charting-library/reference/troubleshooting) for more help.

[Interactive chart example](https://docs.lumencharts.com/charting-library/getting-started/quickstart) — runs in a browser with synthetic data.

[Connect real data →](https://docs.lumencharts.com/charting-library/datafeed)

---
Documentation page: https://docs.lumencharts.com/charting-library/getting-started/quickstart


---

<!-- Public documentation export; not library implementation source. -->
# Lifecycle and frameworks

Each widget belongs to the view that hosts it. Create it once, wait until it's ready, and remove it when the view goes away.

## Two "ready" moments

`onChartReady(callback)` tells you the chart API is ready to use. `headerReady()` tells you when you can add header controls. A ready chart may still be waiting for data from the network. To know when bars have arrived, use the chart's data status or subscriptions.

```js
widget.onChartReady(() => {
  const chart = widget.activeChart();
  const owner = {};
  const handle = chart.onDataLoaded();
  const onLoaded = () => console.log('Bars available');
  handle.subscribe(owner, onLoaded);
  // Before disposal: handle.unsubscribe(owner, onLoaded);
});
```

## Avoid charts that appear too late

If you load the runtime asynchronously, make sure the host view is still on screen before you create the widget. Say the user changes route while the script is still downloading. When the download finishes, it shouldn't create a chart that nobody can see. Keep one generation counter or cancellation token for each mount.

## Clean up everything you started

Call `widget.remove()`, then close your datafeed's subscriptions, timers and network requests. Remove your own subscriptions and resize observers too. Before you retry after a failure, remove the failed widget first. Removing the visible iframe doesn't stop timers that your own code started.

When you load a saved layout, let the chart finish loading it before you apply separate history checkpoints. An undo stack is no substitute for real saving.

## Framework integrations

The runtime works with any framework. Each host component should own exactly one widget and its datafeed, from creation to cleanup.

| Host | Create the chart in | Clean up in |
| --- | --- | --- |
| Plain HTML/JS | After the document loads and the container exists | Remove the widget and stop the datafeed |
| Vue | `onMounted` | `onBeforeUnmount` |
| Nuxt | A client-only component, once mounted | The same Vue cleanup |
| React | An effect, using a DOM ref | The effect's cleanup, including the extra remount in development |

Only load runtime scripts in the browser. Type-only imports are safe at build time. Importing browser code during server-side rendering can fail because `window` or `document` doesn't exist there.

## React

Create the widget once the container has mounted, and remove it in the same effect's cleanup. In development, React may mount, clean up and mount again. Make sure the first load, if it's still pending, doesn't create a chart after cleanup has run.

```tsx
import { useEffect, useRef } from 'react';
import { loadChartLibrary } from './chart-loader';
import { createDemoDatafeed } from './sample-datafeed';
export function Chart() {
  const container = useRef<HTMLDivElement>(null);
  useEffect(() => {
    let cancelled = false;
    let widget: { remove(): void } | undefined;
    const feed = createDemoDatafeed();
    loadChartLibrary('/lumen_charting_library/').then(library => {
      if (cancelled || !container.current) return;
      widget = new library.widget({
        container: container.current, library_path: '/lumen_charting_library/',
        datafeed: feed.datafeed, symbol: 'AAPL', interval: '1D',
        locale: 'en', autosize: true,
      });
    }).catch(console.error);
    return () => { cancelled = true; widget?.remove(); feed.dispose(); };
  }, []);
  return <div ref={container} style={{ height: 560 }} />;
}
```

In a real component, replace `console.error` with an error state and a retry option. You write the loader and sample datafeed yourself as part of your integration; they don't come from React. For chart commands that change often, call them on the existing widget. Don't add them all to the mount effect's dependencies, or the chart will be rebuilt each time.

## Vue and Nuxt

Create the chart in a client-side lifecycle hook. If loading is asynchronous, check that the component is still mounted before creating the widget.

```vue
<script setup lang="ts">
import { onMounted, onBeforeUnmount, ref } from 'vue';
import { loadChartLibrary } from './chart-loader';
import { createDemoDatafeed } from './sample-datafeed';
const container = ref<HTMLElement>();
let cancelled = false;
let widget: { remove(): void } | undefined;
const feed = createDemoDatafeed();
onMounted(async () => {
  const library = await loadChartLibrary('/lumen_charting_library/');
  if (cancelled || !container.value) return;
  widget = new library.widget({
    container: container.value, library_path: '/lumen_charting_library/',
    datafeed: feed.datafeed, symbol: 'AAPL', interval: '1D',
    locale: 'en', autosize: true,
  });
});
onBeforeUnmount(() => {
  cancelled = true;
  widget?.remove();
  feed.dispose();
});
</script>
<template><div ref="container" style="height:560px" /></template>
```

The loader and datafeed are helpers you write as part of your integration. They aren't Vue APIs, and they aren't library source you can download. Use your authorized copy of the runtime and build these helpers in your app. If the loader fails, show the error in your UI and offer a way to retry.

### Nuxt

Wrap the host in `<ClientOnly>` or use a client component, and keep browser imports on the client side. Serve the runtime files from your app's configured asset path, and remember any deployment prefix. Avoid route watchers that rebuild the chart every time some unrelated state changes.

[Lifecycle example](https://docs.lumencharts.com/examples?example=lifecycle)

---
Documentation page: https://docs.lumencharts.com/charting-library/getting-started/lifecycle
