npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@coralogix/roku

v0.2.0

Published

Official Coralogix SDK for Roku

Readme

Official Coralogix SDK for Roku

npm version

Real User Monitoring for Roku channels: sessions, logs, errors, crashes, views and network requests, sent to Coralogix. Requires Roku OS 11 or later; crash reporting requires Roku OS 13 or later.

Links

Installation

ropm is a package manager for Roku, based on npm. If your channel doesn't use ropm yet, follow its installation guide. Then install the SDK:

ropm install @coralogix/roku

ropm prefixes the SDK's functions with coralogix_roku_, as used throughout this page.

Usage

Call coralogix_roku_initialize in main.brs, right after screen.show():

sub Main()
    screen = CreateObject("roSGScreen")
    port = CreateObject("roMessagePort")
    screen.setMessagePort(port)
    screen.CreateScene("MainScene")
    screen.show()

    coralogix_roku_initialize({
        public_key: "your-rum-public-key",
        application: "my-channel",
        coralogixDomain: "EU2",
        version: "1.4.0",
        environment: "production",
        labels: { tier: "premium" },
        user_context: { user_id: "user-1", user_name: "Jane", user_email: "[email protected]" },
        sessionConfig: { sessionSampleRate: 100, inactivityTimeoutMinutes: 120 }
    }, screen.getGlobalNode())

    ' ...the rest of your channel setup
end sub

coralogix_roku_initialize returns true when the SDK starts. If an option is invalid, it returns false, sends nothing, and the console names the option. The SDK skips a label with an unsupported value, or a pattern that doesn't compile, and warns on the console.

After initialize, every component reaches the SDK as m.global.cxRum:

m.global.cxRum.callfunc("reportInfo", "home screen shown")

In a Task, read it once and keep the reference:

sdk = m.global.cxRum
sdk.callfunc("reportInfo", "catalog loaded")

m.global.cxRum is invalid before initialize and after shutdown, and a callfunc on invalid crashes the thread. Guard every call that can run outside that window:

if m.global.cxRum <> invalid then m.global.cxRum.callfunc("reportInfo", "home screen shown")

A scene's init() runs during CreateScene, before initialize, so it always sees invalid. Report from init() only after Main signals that the SDK is ready, for example through an interface field your scene observes and Main sets after coralogix_roku_initialize returns.

A reference kept in a Task stays safe after shutdown: report calls on it do nothing. Every call returns immediately; the SDK sends records in batches from its own thread.

Configuration options

| Option | Type | Required | Description | | --- | --- | --- | --- | | public_key | String | Yes | Your RUM public key. | | application | String | Yes | Your application name in Coralogix. | | coralogixDomain | String | Yes* | Your Coralogix region: EU1, EU2, US1, US2, US3, AP1, AP2, AP3. | | coralogixDomainUrl | String | Yes* | Your ingress URL, used instead of coralogixDomain. | | version | String | No | Your channel's version. Defaults to the version in your manifest. | | environment | String | No | For example production or staging. | | labels | Object | No | Labels added to every record. Values are strings, numbers or booleans. | | user_context | Object | No | The viewer: user_id, user_name, user_email, account_id, account_name, user_metadata. Change it later with setUserContext. | | sessionConfig | Object | No | { sessionSampleRate, inactivityTimeoutMinutes }. sessionSampleRate: the percentage of sessions to record, 0–100. Default 100. inactivityTimeoutMinutes: how long a session lasts with no activity, a whole number of minutes from 15 to 240. Default 120 (2 hours). See Sessions. | | instrumentations | Object | No | { custom, errors, network }, all true by default. See Instrumentations. | | ignoreUrls | Array | No | Network requests not to report. See Ignore URLs. | | ignoreErrors | Array | No | Errors not to report. See Ignore errors. | | ignoredExitEvents | Array | No | Exit codes that are not crashes, such as "EXIT_SETTINGS_UPDATE", added to the defaults: EXIT_UNKNOWN, EXIT_POWER_MODE, EXIT_IDLE_AUTO_EXIT, EXIT_DIAL_DELETE, EXIT_USER_KILL, EXIT_USER_NAV. A Home press is already not a crash. | | traceParentInHeader | Object | No | { enabled, options: { allowedTracingUrls } }. See Traces. | | batchConfig | Object | No | { scheduledDelayMillis }: how often the SDK sends records, 2000–30000 ms. Default 2000. | | proxyUrl | String | No | Send records to your own relay. The SDK passes the Coralogix address in a cxforward query parameter. | | ignoreProxyUrlParams | Boolean | No | Send to proxyUrl without the cxforward parameter. Default false. | | debug | Boolean | No | Print SDK activity to the device console. Default false. See Troubleshooting. |

* Set one of coralogixDomain or coralogixDomainUrl.

Instrumentations

Pass false to turn one off:

| Key | Covers | | --- | --- | | custom | Custom logs: reportLog and the level methods | | errors | reportError and crash reports | | network | CxUrlTransfer and reportNetworkRequest. When false, the SDK adds no traceparent header. |

coralogix_roku_initialize({
    ' ...
    instrumentations: { network: false }
}, screen.getGlobalNode())

Custom logs

m.global.cxRum.callfunc("reportInfo", "playback started", {
    data: { asset_id: "movie-8842", bitrate: 4500 },
    labels: { feature: "playback" }
})

| Method | Severity | | --- | --- | | reportDebug | Debug | | reportVerbose | Verbose | | reportInfo | Info | | reportWarn | Warning | | reportErrorLog | Error | | reportCritical | Critical |

Each takes a message and optional { data, labels }. The SDK cuts a message at 2048 characters, and drops data over 3584 characters with a console warning. When the level is a variable, use reportLog with a value from getSeverity:

severity = m.global.cxRum.callfunc("getSeverity")
m.global.cxRum.callfunc("reportLog", severity.WARN, "cache miss", { data: { key: "home" } })

[!NOTE] BrightScript lowercases associative-array keys, so data: { assetId: 1 } arrives in Coralogix as assetid. Use snake_case keys, or build the object case-sensitive before adding any keys:

data = CreateObject("roAssociativeArray")
data.SetModeCaseSensitive()
data["assetId"] = 1

SetModeCaseSensitive() works only on a new object, before you add keys, and doesn't carry into nested objects: set it on each level. The same applies to labels.

Error reporting

Report errors from your try/catch. The SDK sends the message, error code and stack trace:

try
    startPlayback(asset)
catch e
    m.global.cxRum.callfunc("reportError", e, {
        data: { asset_id: asset.id },
        labels: { feature: "playback" }
    })
end try

Report a failure that didn't throw, as an object or a message:

m.global.cxRum.callfunc("reportError", { message: "no payment method on file", errorType: "PaymentError" })
m.global.cxRum.callfunc("reportError", "playlist arrived empty")

Set a short errorType for each kind of failure, such as PaymentError, and give thrown errors one too: throw { message: "checkout failed", errorType: "PaymentError" }. An error's data is capped at 2048 characters.

Ignore errors

ignoreErrors drops errors whose message matches. A string matches anywhere in the message; a regular expression is written between slashes, with the flags i, m, s and x:

coralogix_roku_initialize({
    ' ...
    ignoreErrors: ["expected timeout", "/^Network error/i"]
}, screen.getGlobalNode())

Crashes

The SDK reports crashes automatically on the next launch, with the exit code and the last 20 console lines before the crash. It doesn't report a crash followed by a device restart.

[!WARNING] The SDK sends these console lines to Coralogix. Keep tokens and personal data out of your console output.

| error_type | Meaning | | --- | --- | | BrightScriptCrash | The channel's code crashed | | OutOfMemory | The channel ran out of memory | | SystemKill | The OS closed the channel | | Crash | Any other unexpected exit |

View tracking

Name each screen when it is shown. Records after it carry the view name:

m.global.cxRum.callfunc("startView", "Home")
m.global.cxRum.callfunc("startView", "Player")   ' replaces Home
m.global.cxRum.callfunc("endView")               ' clears the current view

Labels

setLabels adds labels, or changes existing ones, on every record that follows:

' initialized with labels: { tier: "free" }
m.global.cxRum.callfunc("setLabels", { tier: "premium", ab_test: "b" })

labels = m.global.cxRum.callfunc("getLabels")   ' { tier: "premium", ab_test: "b" }

Labels passed to a single log or error apply to that record only. Channel-wide labels (initialize plus every setLabels) are capped at 512 characters: the SDK ignores a setLabels call that would go over the cap, and warns on the console. Keys are lowercased as described under Custom logs.

User context

Set the viewer after a sign-in, or clear it after a sign-out. Records from then on carry the new user:

m.global.cxRum.callfunc("setUserContext", {
    user_id: "user-1",
    user_name: "Jane",
    user_email: "[email protected]",
    user_metadata: { plan: "family" }
})

m.global.cxRum.callfunc("setUserContext", {})   ' signed out

setUserContext replaces the whole user: a field you don't pass is cleared. Fields: user_id, user_name, user_email, account_id, account_name (strings) and user_metadata (an object). The SDK refuses a call with an unknown field and warns on the console.

Network requests

Use CxUrlTransfer instead of roUrlTransfer in the Task that makes your requests. Its methods are the same, and the SDK reports every request with its method, URL, status code, duration and size.

[!WARNING] Don't callfunc from the render thread into the Task that makes requests while a request is in flight. Each side waits for the other and the channel hangs.

  1. Load it in the Task. A component can only call functions from scripts it loads itself, so this step is required. In the Task's XML:

    <script type="text/brightscript" uri="pkg:/source/roku_modules/coralogix_roku/instrumentations/network/CxUrlTransfer.brs" />

    Or, if the Task's code is in a BrighterScript (.bs) file, import it there:

    import "pkg:/source/roku_modules/coralogix_roku/instrumentations/network/CxUrlTransfer.brs"
  2. Create it where you created roUrlTransfer:

    ut = coralogix_roku_CxUrlTransfer(m.global)
    ut.SetUrl("https://api.example.com/catalog")
    body = ut.GetToString()
  3. For async requests, pass each roUrlEvent to ReportEvent:

    ut.SetMessagePort(port)
    ut.AsyncGetToString()
    
    msg = wait(0, port)
    if type(msg) = "roUrlEvent"
        ut.ReportEvent(msg)
    end if

To report a request made another way:

m.global.cxRum.callfunc("reportNetworkRequest", {
    method: "GET", url: "https://api.example.com/catalog", statusCode: 200, durationMs: 184
})

Optional fields: startTime (epoch ms), failureReason and responseContentLength (bytes).

Ignore URLs

ignoreUrls drops network requests whose URL matches. A string must equal the URL; a regular expression is written between slashes, with the flags i, m, s and x:

coralogix_roku_initialize({
    ' ...
    ignoreUrls: [
        "https://api.example.com/health",          ' this exact URL
        "/^https:\/\/analytics\.example\.com\//"   ' any URL on this host
    ]
}, screen.getGlobalNode())

Traces

Add a W3C traceparent header to requests to your backends, so their traces join the RUM session. allowedTracingUrls takes strings and regular expressions, matched the same way as ignoreUrls:

coralogix_roku_initialize({
    ' ...
    traceParentInHeader: {
        enabled: true,
        options: { allowedTracingUrls: ["/^https:\/\/api\.example\.com\//"] }
    }
}, screen.getGlobalNode())

The SDK adds the header to requests made with CxUrlTransfer. Without allowedTracingUrls, every such request gets it, including third parties, except URLs in ignoreUrls. If you set traceparent or tracestate yourself, the SDK leaves your headers as they are.

Sessions

A session starts at initialize and ends after either of these:

| Ends after | Counts as activity | | --- | --- | | 2 hours of inactivity (set with sessionConfig.inactivityTimeoutMinutes, 15–240 minutes) | a key press on the remote, or reportUserActivity | | 4 hours in total | nothing extends it |

The next record after a session ends starts a new session instead of being dropped. The new session links to the one before it through prev_session. Each new session is sampled again, so with a sessionSampleRate below 100 it may not be recorded. An inactivityTimeoutMinutes of 240 matches the 4-hour limit, so in practice only that limit ends a session.

Video playback produces no key presses, so a film longer than the inactivity timeout with no remote use starts a new session part-way through. To keep one session for the whole film, report activity while content plays, for example on each playback progress update:

m.global.cxRum.callfunc("reportUserActivity")   ' returns the session id

To end the current session and start a new one, for example when the viewer signs out:

newSessionId = m.global.cxRum.callfunc("createNewSession")

Shutdown

m.global.cxRum.callfunc("shutdown")

Stops the SDK. It drops records not yet sent and reports nothing more.

Reading SDK state

Read-only calls, for showing or checking what the SDK reports:

| Call | Returns | | --- | --- | | getSessionId | The current session id, or "" once the session has ended and the next record has not yet started a new one | | getConfig | The resolved configuration | | getSessionContext | The session block sent with every record | | getDeviceContext | The device block sent with every record | | getDeviceState | The current network, memory and uptime readings |

To see each batch land, observe cxExportResult:

m.global.cxRum.observeField("cxExportResult", "onExportResult")

sub onExportResult(event as object)
    result = event.getData()
    print "post "; result.status; " — "; result.chars; " chars"
end sub

status is the HTTP status of the upload; 0 or below means no response came back at all. chars is the payload size in characters.

Troubleshooting

By default the SDK prints only warnings and errors to the device's debug console: an option it rejected, a call it ignored, a batch that failed. Set debug: true to also see what it does:

  • initialized, with the session id, when the SDK starts
  • every record, exactly as the SDK sends it
  • each batch and its HTTP status (post ok / post failed)

What the SDK sends to Coralogix doesn't change. Watch the console with:

nc <roku-ip> 8085
  • initialize returned false: the console names the wrong option.
  • No data in Coralogix: look for post failed. A 4xx or 5xx status means Coralogix refused the batch; check public_key and coralogixDomain. A status of 0 or below means no response came back at all (-28 a timeout, -6 a DNS failure): check the network, not the key.
  • post ok and still no data: Coralogix can accept a batch and still drop its records. Check the device's date and time, sessionSampleRate, and ignoreUrls and ignoreErrors.
  • Nothing printed at all: check that coralogix_roku_initialize runs after screen.show() and gets screen.getGlobalNode().
  • Finding a session in Coralogix: the initialized line has its id, or call m.global.cxRum.callfunc("getSessionId") (empty once the session has ended).

License

Apache-2.0