<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Toni Petov</title>
    <description>The latest articles on DEV Community by Toni Petov (@tpetrov9).</description>
    <link>https://dev.to/tpetrov9</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F205272%2F9847157a-94a8-4ffa-9ae5-00b48c40b0e1.jpeg</url>
      <title>DEV Community: Toni Petov</title>
      <link>https://dev.to/tpetrov9</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/tpetrov9"/>
    <language>en</language>
    <item>
      <title>Interop.io &amp; io.Connect Glossary</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Thu, 04 Dec 2025 15:19:39 +0000</pubDate>
      <link>https://dev.to/tpetrov9/interopio-ioconnect-glossary-43h3</link>
      <guid>https://dev.to/tpetrov9/interopio-ioconnect-glossary-43h3</guid>
      <description>&lt;p&gt;If you are new to io.Connect and the interop.io ecosystem you may wonder what some of the acronyms and nicknames you see are. I tried to put together a glossary to help:&lt;/p&gt;

&lt;h2&gt;
  
  
  Acronyms &amp;amp; shorthand
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IOCD&lt;/strong&gt; - shorthand for &lt;strong&gt;io.Connect Desktop&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IOCB&lt;/strong&gt; - shorthand for &lt;strong&gt;io.Connect Browser&lt;/strong&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;ENV‑REG&lt;/strong&gt; - The “environment‑region” folder name in user paths (e.g., &lt;code&gt;UserData/DEMO-INTEROP.IO&lt;/code&gt;). You’ll see it in examples like &lt;code&gt;.../UserData/&amp;lt;ENV&amp;gt;-&amp;lt;REG&amp;gt;/apps&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;BBG&lt;/strong&gt; - Bloomberg adapter namespace (e.g., &lt;code&gt;T42.BBG.*&lt;/code&gt;); shows up in method names if you use the Bloomberg integration.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;FDC3&lt;/strong&gt; - an open interoperability standard for &lt;strong&gt;financial services&lt;/strong&gt; , building apps for the trading/analysis desktop. It’s created and governed in FINOS and promoted across the industry as a common way for apps to discover each other&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;GD&lt;/strong&gt; - Legacy shorthand for &lt;em&gt;Glue Desktop / Glue42 Desktop&lt;/em&gt; (today: &lt;strong&gt;io.Connect Desktop&lt;/strong&gt; ). Can still appear in method namespaces (&lt;code&gt;T42.GD.*&lt;/code&gt;), query params (&lt;code&gt;?gd&lt;/code&gt;), or some repo names. &lt;strong&gt;Glue42&lt;/strong&gt; was the previous name of the product that evolved into &lt;strong&gt;io.Connect Desktop&lt;/strong&gt; after the merge with &lt;strong&gt;Finsemble&lt;/strong&gt; , that formed &lt;strong&gt;interop.io&lt;/strong&gt; in 2023.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;T42&lt;/strong&gt; - Legacy namespace/prefix you can see in method names, logs, etc. It comes from the name &lt;strong&gt;Tick42&lt;/strong&gt; (the company behind &lt;strong&gt;Glue42&lt;/strong&gt; ) that merged with &lt;strong&gt;Finsemble.&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;FSBL (Finsemble)&lt;/strong&gt; - The other company that merged into &lt;strong&gt;interop.io&lt;/strong&gt;. &lt;strong&gt;Finsemble&lt;/strong&gt; was (and is) also the name of the company’s desktop interop platform.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Platform building blocks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Interop‑enable an app&lt;/strong&gt; - To “interop-enable” an app means wiring it to io.Connect so that the latter can launch/manage it and the app can talk to others. Give it the client library (auto-inject via &lt;code&gt;system.json → windows.autoInjectAPI&lt;/code&gt; or import) and initialize to get the &lt;code&gt;io&lt;/code&gt; object. This enables apps to discover each other, share context, and hand off tasks without brittle one-offs or copy/paste, so workflows move smoothly across windows.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;App Stores&lt;/strong&gt; - Where app definitions come from. Can be local folders, REST, or &lt;strong&gt;io.Manager&lt;/strong&gt;. IOCD loads all defined stores on startup.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;io.Connect Gateway&lt;/strong&gt; - The message bus that carries inter‑app and app↔platform messages (WebSockets by default).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;App Definition&lt;/strong&gt; - A JSON file that describes an app (name, type like &lt;code&gt;window&lt;/code&gt;/&lt;code&gt;exe&lt;/code&gt;/&lt;code&gt;node&lt;/code&gt;, URL or path, sizing, etc.). Place it under the user apps folder to make the app launchable from IOCD.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Launchpad / Launcher&lt;/strong&gt; - The built‑in UI navigation sidebar that lists apps and lets users start them.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Application Adapters&lt;/strong&gt; - Prebuilt integrations (Excel, Outlook, Bloomberg, Salesforce, etc.) that expose those apps’ actions to your interop‑enabled apps.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;IODesktop()&lt;/strong&gt; - The JavaScript factory function you call to initialize the io.Connect API inside an app. Returns the &lt;code&gt;io&lt;/code&gt; object.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Polyfill (Finsemble)&lt;/strong&gt; - a &lt;strong&gt;compatibility layer in the Finsemble Seed&lt;/strong&gt; that lets Finsemble projects run on &lt;strong&gt;io.Connect Desktop (IOCD)&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If there’s anything I’ve missed, please post below so we can add it.&lt;/p&gt;

&lt;p&gt;&lt;small&gt;1 post - 1 participant&lt;/small&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.interop.io/t/interop-io-io-connect-glossary/385" rel="noopener noreferrer"&gt;Read full topic&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ioconnectdesktop</category>
    </item>
    <item>
      <title>How to Build Interop That People Actually Use</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Wed, 26 Nov 2025 00:37:55 +0000</pubDate>
      <link>https://dev.to/interopio/how-to-build-interop-that-people-actually-use-16pe</link>
      <guid>https://dev.to/interopio/how-to-build-interop-that-people-actually-use-16pe</guid>
      <description>&lt;p&gt;In &lt;a href="https://community.interop.io/t/from-strategy-to-poc-setting-up-desktop-interop-that-actually-works/303" rel="noopener noreferrer"&gt;Part 1&lt;/a&gt;, I covered the planning work that prevents disasters before you write a single line of code: identifying the right workflows, understanding integration complexity, and establishing governance. Now let’s talk about execution - how to actually build interop that scales and gets adopted.&lt;/p&gt;

&lt;p&gt;Because once you move from planning to building, the stakes change completely, and this is where technical decisions compound. It’s not just whether your integrations work, but whether they’re maintainable, whether users trust them, and whether the architecture you choose today becomes technical debt tomorrow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep Architecture Simple
&lt;/h2&gt;

&lt;p&gt;Architecture is inherently complex. We’re solving problems across systems that were never meant to talk to each other. But sometimes, it’s not just complex, it’s &lt;em&gt;complicated&lt;/em&gt;. And there’s a difference.&lt;/p&gt;

&lt;p&gt;The extra complication usually comes from things we inherit like legacy systems, rushed timelines, or designs that worked in one context but don’t scale. You might build something that works perfectly for one business unit, then replicate it everywhere without thinking holistically. So again, you end up with a patchwork of siloed mini-projects that don’t play well together.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Micro Frontend Trap
&lt;/h2&gt;

&lt;p&gt;Take micro frontends as an example. They can be powerful when used wisely. But too often, teams slice their UI into dozens of tiny apps, each with its own state, services, and dependencies. Or worse, they overload the UI layer, using it as a caching layer or even a mini backend.&lt;/p&gt;

&lt;p&gt;At first, it feels productive. Things ship faster. Components are reusable. Everything’s “decoupled.”&lt;/p&gt;

&lt;p&gt;Fast-forward six months or a year and you’ve got ten teams coordinating versioning, dependency conflicts, inconsistent user experiences, and performance issues.&lt;/p&gt;

&lt;p&gt;That’s when complexity stops being useful and starts being a liability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start Simple, Expand with Confidence
&lt;/h2&gt;

&lt;p&gt;Here’s the rule for interop-heavy environments: start with the cleanest, most minimal architecture that meets requirements. Fewer moving parts mean fewer places for things to break. It’s always easier to add complexity later when you have a real reason than to untangle a mess after everything’s in production.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://canada1.discourse-cdn.com/flex028/uploads/interopio/original/1X/279d507f3a3f2bf91d165dc6d4cc3f46b7001d80.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbb1ro2b1jc0pb1hc1wf6.png" width="539" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Build iteratively:
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Phase 1:&lt;/strong&gt; Get the basics working. Two apps sharing context. One workflow functioning end-to-end.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 2:&lt;/strong&gt; Users try it. What works? What doesn’t? Refine based on feedback.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3:&lt;/strong&gt; Add more applications and workflows systematically. Each addition builds on lessons learned.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 4:&lt;/strong&gt; Now you have real usage data. Optimize where it actually matters.&lt;/p&gt;

&lt;p&gt;This reduces risk and provides feedback early enough to make meaningful changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Design for Humans, Not Just Systems&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You can have flawless architecture, perfect data flows, and APIs that communicate beautifully. Five applications syncing context behind the scenes, messages flowing, events firing exactly as designed.&lt;/p&gt;

&lt;p&gt;And users may still use it the wrong way and even cause support burden.&lt;/p&gt;

&lt;p&gt;Why? Because technical integration is not the same thing as usability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What Users Need&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visibility:&lt;/strong&gt; Users need to see what’s happening. When context is shared, show it. When data is syncing, indicate it. When an action triggers multiple apps, make it clear what’s connected.&lt;/p&gt;

&lt;p&gt;This doesn’t mean cluttering the interface. It means providing appropriate feedback at the right moments like visual indicators when apps are linked, brief confirmations when context is shared, clear status when something is loading.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Control:&lt;/strong&gt; Nothing kills adoption faster than a system that feels like it’s driving itself. Give users the ability to see what apps are connected, disconnect when needed, trigger actions manually when automatic isn’t right, and undo when things go wrong.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Clarity:&lt;/strong&gt; Design interactions that make sense in the user’s mental model, not the system’s technical model.&lt;/p&gt;

&lt;p&gt;Bad: “App has raised intent fdc3.ViewChart for instrument context”&lt;br&gt;&lt;br&gt;
Good: “Opening chart for AAPL”&lt;/p&gt;

&lt;p&gt;Users don’t think in terms of “intents” and “context objects.” They think in terms of clients, securities, portfolios, orders. Your UX should speak their language.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UX Is the Delivery Mechanism&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you’re building interop, don’t stop at making it work. Make it clear. Build for confidence and control. Integration is powerful, but if users can’t see what happened, understand why it happened, or control it when they need to, they’ll misuse or abandon it.&lt;/p&gt;

&lt;p&gt;Design matters because at the end of the day, you’re solving for humans.&lt;/p&gt;

&lt;h2&gt;
  
  
  Golden Rules
&lt;/h2&gt;

&lt;p&gt;Here’s what separates successful interop implementations from failed ones:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Focus on workflows, not technology&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Integrate because it solves problems, not because you can.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Start simple, avoid analysis paralysis&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
The simplest architecture that works is usually the right architecture. Complexity is costly. Don’t try to design the perfect system on paper.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Establish clear governance&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Structure enables speed. Chaos slows everyone down.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Design for humans first&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
If users can’t understand and control it, they won’t use it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Iterate gradually&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
Avoid big-bang rollouts and analysis. Phased approaches reduce risk and enable learning.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. Think about performance and compliance from day one&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
These aren’t things you add later. They’re foundational.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;Interop isn’t just about APIs and windows linking together. It’s about creating a system that people trust, that scales, and that actually solves problems.&lt;/p&gt;

&lt;p&gt;The difference between success and failure isn’t usually the technology, but whether you kept architecture manageable, designed for how humans actually work, and built iteratively with real feedback.&lt;/p&gt;

&lt;h3&gt;
  
  
  Catch up on Part 1:
&lt;/h3&gt;

&lt;p&gt;If you haven’t already, I recommend you to check out the &lt;a href="https://community.interop.io/t/from-strategy-to-poc-setting-up-desktop-interop-that-actually-works/303" rel="noopener noreferrer"&gt;first article&lt;/a&gt;, where we explored, setting goals, strategy and governance. Let us know if you’re interested in discussing real-world use cases and diving deeper into what we’ve seen working before (and what to better avoid).&lt;/p&gt;

&lt;p&gt;Have you hit other obstacles that we didn’t cover? Were there things that didn’t go according to plan, but worked in the end? Any surprising user stories or neat workarounds you can share?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.interop.io/t/how-to-build-interop-that-people-actually-use/357" rel="noopener noreferrer"&gt;Read full topic&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ioconnectdesktop</category>
    </item>
    <item>
      <title>Performance considerations for desktop interop systems</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Tue, 25 Nov 2025 08:24:36 +0000</pubDate>
      <link>https://dev.to/interopio/performance-considerations-for-desktop-interop-systems-12eo</link>
      <guid>https://dev.to/interopio/performance-considerations-for-desktop-interop-systems-12eo</guid>
      <description>&lt;h2&gt;
  
  
  Tips for troubleshooting bottlenecks and optimizing resource usage
&lt;/h2&gt;

&lt;p&gt;Optimization of performance in desktop interop deployments impacts end-user productivity and reduces the total cost of operation. Here at interop.io, we’ve identified five key factors that influence performance in real-world desktop environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;1. Disk footprint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Desktop interop systems like io.Connect Desktop are typically installed as launchable applications on end users’ computers or VDIs. The amount of disk space required for installation varies depending on the specific feature set in use. For instance, the inclusion of various adapters (e.g, Office Adapter) increases the required disk space. System logging also requires adequate disk space. The parameters of io.Connect’s &lt;a href="https://community.interop.io/t/understanding-logs-in-io-connect/36#p-43-system-log-rotation-15" rel="noopener noreferrer"&gt;log rotation&lt;/a&gt; (zipping and then removing old files) can be adjusted as necessary to ensure that systems never run low on disk space.&lt;/p&gt;

&lt;h4&gt;
  
  
  Free Trial vs. Production size
&lt;/h4&gt;

&lt;p&gt;Note that trial versions of io.Connect Desktop have larger disk footprint than production versions. This is because the trial version includes io.Connect Desktop’s full suite of adapters and libraries. We optimize this size when configuring your production installer.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;2. Memory footprint&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The amount of memory used by a desktop system depends on 4 factors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Baseline system memory&lt;/strong&gt;. This is the memory required by the system’s core components and service layers. This is a fixed amount which cannot be optimized.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;em&gt;App&lt;/em&gt; memory requirements&lt;/strong&gt;. This is the most important factor. Each app that is launched inside the desktop will have its own memory requirements. This memory usage is typically independent of the underlying platform. For instance, an app running in a Chrome tab will use the same amount of memory running in an io.Connect window.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;System overhead per app&lt;/strong&gt;. The desktop system will add additional memory for each running app. This includes the cost for running the underlying rendering engine (e.g. chromium instances, webview2 instances) as well as the desktop system’s own memory requirements (such as client-side APIs that are resident in the app, e.g. via preloads). This overhead is typically the same in Chrome and io.Connect.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Systemwide heap&lt;/strong&gt;. App usage of features such as stored contexts, application configs, etc will result in some memory growth at the system level. The exact amount depends both on the behaviors of apps as well as the heuristics of the system itself. This memory is usually small unless very large contexts or extensive lists of apps are used.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It is important to note that overall memory requirements of the desktop don’t impact end-user experience until memory requirements overshoot the hardware’s capacity, at which point hardware systems can slow down due to memory swapping. Some VDI systems can fail outright when memory requirements are exceeded. Modern hardware typically provides 16GB and 32GB options at low cost. VDI systems with these capacities can cost $200 - $400 per month, per end user.&lt;/p&gt;

&lt;h4&gt;
  
  
  Greedy memory allocation
&lt;/h4&gt;

&lt;p&gt;A key understanding when evaluating memory usage is that modern operating systems use a “greedy” approach to allocating memory. App memory may swell in size as the operating system determines the app’s needs, and the OS will not necessarily reclaim that memory until it is needed. In a system with 32GB of memory, it may be the case that the operating system rarely needs to reclaim memory, and so a large app like io.Connect or Chrome may be observed to have very high memory usage, even though much of this memory is not “active”.&lt;/p&gt;

&lt;h4&gt;
  
  
  Considerations
&lt;/h4&gt;

&lt;p&gt;A key value proposition of desktop interop is the ability to run multiple apps at once in a “composed” view. Such a view can be a layout (multiple windows organized across one or more monitors) or a workspace (multiple apps organized into frames within a single window). With more windows comes a requirement for more memory, each app requiring its own heap as well as the memory requirements of the underlying rendering engine (Chromium). For large layouts across multiple monitors, this can result in a claim for several gigabytes of memory.&lt;/p&gt;

&lt;h4&gt;
  
  
  Individual app consumption
&lt;/h4&gt;

&lt;p&gt;It is important to understand the memory requirements of the individual apps that will be running simultaneously on the screen. For instance, an app that requires 400MB of memory running in a browser tab might never seem to cause any problems. But once released within io.Connect, users can decide to open several copies of the same app (now that they can organize these copies side-by-side), which then multiplies the amount of memory required. Optimizing memory usage of your business apps may therefore be necessary when system resources are constrained.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;3. CPU and networking overhead&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;In much the same way as a browser does, the bulk of CPU usage is generally from the applications that reside within the desktop. A desktop system does add some CPU and networking overhead via its own underlying processes, most of which occur only during system startup. Some overhead occurs when client APIs are used within the application space. For instance, applications that share context must exchange that context via the system’s services. Those services will use CPU to process and communicate. Generally, the overhead of such systems is low, but in some cases can become noticeable, such as when exchanging large chunks of data, when adding large numbers of app configs, or when saving and restoring complex layouts.&lt;/p&gt;

&lt;p&gt;Delays due to overloaded CPU or network can negatively impact end-user experience. Typically, such situations are remedied through tweaks to API usage or through revisions to app architecture.&lt;/p&gt;

&lt;p&gt;See how to check an app’s CPU and memory usage in the logs - &lt;a href="https://community.interop.io/t/examining-logs-in-practice/110#p-151-how-to-monitor-cpu-and-memory-usage-10" rel="noopener noreferrer"&gt;Examining logs in practice&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;4. Window launch latency&lt;/strong&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  What causes launch latency
&lt;/h4&gt;

&lt;p&gt;Whenever an app is launched, a “renderer” must be instantiated to contain the app. Each of these renderers is its own Chromium instance, launched at the operating system level and observable in task manager. Once the renderer is launched, it immediately loads the app (e.g. downloading its HTML and JavaScript from a network), compiles (V8 engine), and then runs it. The app itself then may have its own initialization process, eventually resulting in display of its contents to the end user (e.g. React rendering). This overall process is essentially the same in interop.io as it is when opening a URL into a new browser tab in Chrome.&lt;/p&gt;

&lt;p&gt;To the end-user, latency is a question of perception. The end user subconsciously measures latency as the time between when they click to launch an app until the time that the app is visible and interactive. As developers, we must break down this experience into individual steps for optimization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time from click to launching of the renderer&lt;/li&gt;
&lt;li&gt;Time from launch of the renderer to running of application code&lt;/li&gt;
&lt;li&gt;Time from running application code to the app being ready for interaction&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Of these, the first step involves the menu itself responding to the end user, and then the desktop system’s internal relays which trigger the launch of a renderer. This first step generally occurs quickly (but should not be ignored.)&lt;/p&gt;

&lt;p&gt;The second step (launching a renderer) depends on the performance of the underlying platform architecture as well as the operating system itself. The amount of time depends in some part on the underlying hardware as this is a CPU-intensive moment. Restoration of a layout may involve launching many apps simultaneously, which can take longer even on powerful systems, particularly if the apps themselves are complex and therefore contending for CPU resources. This is akin to restoring Chrome with dozens of tabs open. Multi-core systems are essential to delivering a better user experience.&lt;/p&gt;

&lt;p&gt;See how to track Layout restoration in the logs here - &lt;a href="https://community.interop.io/t/examining-logs-in-practice/110#p-151-how-to-track-layout-restoration-7" rel="noopener noreferrer"&gt;Examining logs in practice&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Optimizing time to interactive (TTI) and first contentful paint (FCP)
&lt;/h4&gt;

&lt;p&gt;In the third step, the applications themselves must be optimized for quick display. It is common to optimize web apps for metrics such as “Time To Interactive” (TTI) or “First Contentful Paint” (FCP). These same types of optimizations should be considered for apps that run inside a desktop.&lt;/p&gt;

&lt;p&gt;It’s worth noting first that an improvement of 1 or 2 seconds of window launch time is probably not meaningful in the context of a worker’s day. It is only when switching large layouts that an end user generally feels any sense of slowness, and in most of our experience, the biggest gains can be had by optimizing the footprint of individual apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;5. Desktop startup time&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;The final performance consideration is how long the desktop itself takes to launch. An end user is likely to perceive this as the time from double-clicking on the desktop icon to the time when the initial layout is loaded, and all the apps are interactive. As such, a large portion of desktop startup time is &lt;em&gt;actually&lt;/em&gt; layout loading time, which corresponds directly to window launch times as discussed above. But any slowness with window launch times may be exacerbated during startup due to contention with system resources which are booting and initializing at the same time as the apps.&lt;/p&gt;

&lt;p&gt;Desktop startup time depends greatly on the level of “infrastructure” that a firm requires to operate their desktop. By “infrastructure” we mean services which are run during the startup process. In raw form, io.Connect starts in about 10 seconds, but launching and sequencing of background services and other support applications can cause this startup time to balloon. As this sort of infrastructure grows in complexity, CPU and network contention become more likely (as mentioned above), which can further exacerbate startup times. A good practice to avoid these conditions is to limit the number of services by consolidating startup code into fewer, or even a single service.&lt;/p&gt;

&lt;h4&gt;
  
  
  Cost vs. Gain
&lt;/h4&gt;

&lt;p&gt;It is worth noting that system startup time is generally a once-per-day occurrence. A startup time of 30-60 seconds is not ideal, but may not be worth huge effort to optimize unless usage is truly negatively impacted. If systems need to be restarted daily, then this can be accomplished through settings in io.Connect, which would allow the restart to occur during off-hours, so that users are not impacted.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key takeaways for desktop interop performance optimization&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
We must not forget that the user experience interoperability achieves is seamless, but behind the scenes, an often not-so-powerful machine needs to handle dozens of applications at the same time. Sometimes, just one of them can be causing issues and needs to be investigated. In other cases, the cumulative load becomes too great. Balancing disk usage, memory, CPU, and startup processes can significantly improve both performance and user satisfaction. By continuously monitoring resource utilization and refining app configurations, organizations can maintain responsive, scalable desktop environments. In both cases &lt;a href="https://community.interop.io/c/io-insights/6" rel="noopener noreferrer"&gt;io.Insights&lt;/a&gt; can be the tool that makes investigation and performance monitoring much faster, covering every little metric and app trace. See example: &lt;a href="https://community.interop.io/t/track-down-issues-fast-with-io-insights/9" rel="noopener noreferrer"&gt;Track down issues fast with io.Insights&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.interop.io/t/performance-considerations-for-desktop-interop-systems/267" rel="noopener noreferrer"&gt;Read full topic&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ioconnectdesktop</category>
    </item>
    <item>
      <title>Intent Interception use cases</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Tue, 25 Nov 2025 00:37:12 +0000</pubDate>
      <link>https://dev.to/interopio/intent-interception-use-cases-3mbg</link>
      <guid>https://dev.to/interopio/intent-interception-use-cases-3mbg</guid>
      <description>&lt;p&gt;Recently in a couple of meetings, TerryThorsten mentioned how powerful intent interception in io.Connect can be and Kalina Georgieva shared with me some neat use cases where it was handy. So I thought this was worth sharing with the community:&lt;/p&gt;

&lt;h2&gt;
  
  
  Use case 1: Limit intent resolution to the workspace only
&lt;/h2&gt;

&lt;p&gt;When resolving intents in io.Connect Browser, the developer wants to ensure that only applications/windows within the same workspace as the one that raised the intent are considered as possible handlers. The goal is to prevent intents from being handled by applications in other, non-focused workspaces and to avoid requiring extra user interactions.&lt;/p&gt;

&lt;p&gt;By default, the intent resolver considers all possible handlers, including those in other workspaces. While this provides flexibility, it can also lead to confusing behavior, such as intents being handled by apps that are not currently active or visible to the user. The developer, therefore, wanted to restrict intent resolution to the current focused workspace.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Interception achieves the goal
&lt;/h3&gt;

&lt;p&gt;The behavior can be implemented with a plugin interceptor, which intercepts the ‘raise’ operation within the 'intents’ domain. Once the interceptor is in place, it can leverage the interop.io API to identify the appropriate handlers that should be considered. The interceptor then forwards the ‘raise’ command to the Platform along with an array of the filtered handlers, ensuring that only relevant, workspace-local handlers will be provided to the user.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use case 2: App listening to its own intents
&lt;/h2&gt;

&lt;p&gt;When an app in io.Connect raises an intent and also listens for that same intent, the intent resolver UI offers the user the option to resolve the intent using the same app instance that raised it. By default, the FDC3 standard and the io.Connect implementation include all registered handlers for an intent, including the originating app instance, in the resolver UI. There is no explicit exclusion of the originating instance in the FDC3 specification. There might be a reason for that, but some customers prefer to have the app that raised the intent excluded from the listeners list.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Interception achieves the goal
&lt;/h3&gt;

&lt;p&gt;The solution involves intercepting intent resolution calls and filtering out the originating app instance from the handlers list before presenting options to the user. This approach keeps the platform compliant with FDC3 while meeting the specific workflow needs of the app teams.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use case 3: Enforce geographic and compliance restrictions
&lt;/h2&gt;

&lt;p&gt;A compliance-sensitive firm operates in multiple regions. European users run desktop tools that shouldn’t access or display personally identifiable information (PII) contained in chat transcripts or client notes, which are allowed only in the US due to data privacy laws. Yet, the same intents like ViewChatTranscript are available globally.&lt;/p&gt;

&lt;h3&gt;
  
  
  How interception achieves the goal
&lt;/h3&gt;

&lt;p&gt;An interceptor captures raise() operations and evaluates the callerId to determine the user’s region. When a request comes from an EU app, the interceptor either blocks the operation or redirects it to a safer intent, which returns redacted information.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use case 4: Staged rollout of a new client experience
&lt;/h2&gt;

&lt;p&gt;A new version of an intent handler is being tested with a small pilot group. The older version is still in use by everyone else, and both versions are live on the same desktop environment. Need to enable A/B testing and keep the new handler for the pilot group only.&lt;/p&gt;

&lt;h3&gt;
  
  
  How interception achieves the goal
&lt;/h3&gt;

&lt;p&gt;An interceptor is set up to inspect each intent request before it’s dispatched. It checks which app raised the intent and whether that app (or user) is part of the pilot group. If yes, the interceptor reroutes the request to the new v2 handler. All other apps continue using the stable v1 handler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Related documenation:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://docs.interop.io/browser/capabilities/plugins/interception/index.html" rel="noopener noreferrer"&gt;io.Connect Browser Documentation - Plugins &amp;gt; Interception&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.interop.io/browser/capabilities/plugins/interception/index.html#interception_example" rel="noopener noreferrer"&gt;io.Connect Browser Documentation - Plugins &amp;gt; Interception&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.interop.io/browser/reference/javascript/intents/index.html#IntentRequest" rel="noopener noreferrer"&gt;io.Connect Browser Documentation - io.Connect Browser - Intents&lt;/a&gt;&lt;br&gt;
&lt;a href="https://docs.interop.io/browser/capabilities/plugins/setup/index.html" rel="noopener noreferrer"&gt;io.Connect Browser Documentation - Plugins &amp;gt; Setup&lt;/a&gt;&lt;br&gt;
&lt;a href="https://community.interop.io/t/intent-interception-use-cases/367" rel="noopener noreferrer"&gt;Read full topic&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ioconnectbrowser</category>
    </item>
    <item>
      <title>From Strategy to PoC: Setting Up Desktop Interop That Actually Works</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Tue, 18 Nov 2025 08:57:50 +0000</pubDate>
      <link>https://dev.to/interopio/from-strategy-to-poc-setting-up-desktop-interop-that-actually-works-549g</link>
      <guid>https://dev.to/interopio/from-strategy-to-poc-setting-up-desktop-interop-that-actually-works-549g</guid>
      <description>&lt;p&gt;Imagine you just got a new smartphone packed with amazing apps. A beautiful calendar, a notes app with brilliant search and a task manager that’s feature-rich and intuitive. Each one is best-in-class, but they don’t talk to each other. So you’re copy-pasting meeting details, retyping action items, and manually syncing everything.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That’s desktop interop when it goes wrong.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Different teams bring in their favorite applications. Each works brilliantly on its own. But without shared planning or design standards, you end up with powerful tools that don’t click together. Users go back to manual switching, copy-paste, and errors.&lt;/p&gt;

&lt;p&gt;Rolling out interop across an entire firm: multiple business units, workflows, and legacy systems, is where the real value lives. It’s also where complexity multiplies. It’s not just about connecting apps. It’s about orchestrating live data flows across dozens of systems, keeping users in sync, and doing all of that while staying compliant with tight regulatory and internal controls.&lt;/p&gt;

&lt;p&gt;At the interop.io consulting team, we’ve spent over a decade implementing desktop interoperability across Tier 1 banks, hedge funds, and buy-side firms. We’ve seen the full spectrum: from clean, elegant rollouts to absolute chaos. Here I’ll share best practices that will help leaders rescue derailed projects, migrate off legacy platforms, and turn cluttered, fragmented desktops into streamlined environments that actually work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here’s where most projects fail: before a single line of code is even written.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t skip strategy
&lt;/h2&gt;

&lt;p&gt;You got a powerful toolbox that can connect anything in different ways – channels, shared context, intents, FDC3. Someone says, “Let’s connect all our apps!” The idea of smart workflows, data sharing, and seamless integration sounds great. But in all that excitement, you can forget the most important question:&lt;/p&gt;

&lt;h3&gt;
  
  
  Why are we doing this?
&lt;/h3&gt;

&lt;p&gt;Which workflows are we trying to improve? What are the biggest pain points we are trying to solve? Without those answers, you end up integrating tools just because you *can. *&lt;/p&gt;

&lt;p&gt;First, ask relevant questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where are users re-entering the same data into multiple systems?&lt;/li&gt;
&lt;li&gt;What slows people down during high-pressure moments like market open or close?&lt;/li&gt;
&lt;li&gt;Where are we losing time, focus, or accuracy due to app-switching?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you uncover those day-to-day friction points, that’s where interop can &lt;em&gt;really&lt;/em&gt; shine. That’s when you’re solving real problems.&lt;/p&gt;

&lt;p&gt;To do so, bring your stakeholders in early. This isn’t just a developer’s problem or a business wish list. You need alignment across the board: product owners, technical leads, compliance, security, and of course, end-users. Get them all talking &lt;em&gt;before&lt;/em&gt; you start building. Define the goals, agree on how you’ll measure success, and make sure everyone knows who’s responsible for what.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Takeway&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Interop what matters. Start with the pain, not the tech.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Don’t Underestimate Integration Complexity
&lt;/h1&gt;

&lt;p&gt;In the real world, we’re dealing with software written 20 or more years ago, weird homegrown VBA macros, Excel plugins from who-knows-where, and proprietary APIs that were never designed to talk to anything else. Some of these systems don’t even have documentation, let alone a clean way to expose events or accept external triggers. Yes, the interop platform &lt;em&gt;gives&lt;/em&gt; you the tools. But you still have to do the groundwork. That means mapping out the landscape: skipping it will set you up for surprises.&lt;/p&gt;

&lt;p&gt;That’s why we always recommend starting with a Proof of Concept. Not just to prove &lt;em&gt;if&lt;/em&gt; something can work, but &lt;em&gt;how&lt;/em&gt; it should work. Build a small and focused integration. Get real users to try it and watch what they do. And then iterate. A phased approach not only reduces risk, it gives you real-world feedback early enough to make meaningful changes.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://canada1.discourse-cdn.com/flex028/uploads/interopio/original/1X/48d6dfa8d6053ba6d6d1412d6045c63ec676e6d8.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvxwenrx852bhrhuhro7i.png" width="566" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Takeway&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Start small, set clear goals, progressive rollout, and constant feedback. Run a realistic PoC with legacy and modern apps.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Governance and collaboration
&lt;/h1&gt;

&lt;p&gt;Here’s where projects really spiral: governance. Interop isn’t just a shiny frontend project. It cuts across almost every part of the organization: applications, infrastructure, UX, security, compliance, even legal. So unless there’s clear ownership and coordination, what you end up with isn’t integration, but chaos.&lt;/p&gt;

&lt;p&gt;Picture this: you’ve got three different app development teams, all trying to implement interop in their own way. One builds a custom context layer, another hacks together a local framework, and the third just wires up some point-to-point messaging between apps. No one’s talking to each other. No standards. No shared roadmap. In the end you get three incompatible solutions, all branded “interop,” but none of them actually interoperate.&lt;/p&gt;

&lt;p&gt;That’s what happens without governance. Everyone builds in isolation. Silos get a fresh coat of paint, but they’re still silos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://canada1.discourse-cdn.com/flex028/uploads/interopio/original/1X/ceb91ef2dfb98801e01c1b5d8f392b2980c92b3d.png" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnxwg9mozsdr21v05x39r.png" width="549" height="500"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So your project needs leadership and it needs structure. You need someone owning the architecture, someone responsible for platform consistency, and a shared understanding of what “success” looks like across teams.&lt;/p&gt;

&lt;p&gt;At the same time, governance doesn’t need to be heavy-handed, but it &lt;em&gt;does&lt;/em&gt; need to be visible. A big part of that is having a central source of truth: a living repository that tracks everything from onboarded applications and available intents, to shared contexts, methods, and workflows. Most companies use something like Confluence, or an internal wiki for this. It becomes the place where onboarding new apps or defining a new intent goes through a quick review process. Not to slow things down, but to keep things aligned. That’s how you avoid duplication, conflicting designs, and “spaghetti” integrations that nobody wants to own.&lt;/p&gt;

&lt;p&gt;It’s easy to set and forget it, but that’s not enough. Someone needs to own it and keep an eye on it. Most importantly stakeholders must comply with it, so don’t make it too complicated&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Takeway&lt;br&gt;&lt;br&gt;
&lt;strong&gt;Establish governance, standards, and regular architecture reviews. Make sure documentation is up-to-date and ensure new developers are onboarded early on.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1&gt;
  
  
  Before You Start Building
&lt;/h1&gt;

&lt;p&gt;The work you do before writing code determines whether your project succeeds or gets abandoned. Before your team starts integrating:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Identify the specific workflows you’re improving (not “everything”)&lt;/li&gt;
&lt;li&gt;Map your landscape to know what you’re actually working with&lt;/li&gt;
&lt;li&gt;Run a realistic PoC with legacy and modern apps&lt;/li&gt;
&lt;li&gt;Set up a governance structure and a central source of truth&lt;/li&gt;
&lt;li&gt;Get stakeholder alignment across teams&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Next up:&lt;/strong&gt; &lt;strong&gt;&lt;a href="https://community.interop.io/t/how-to-build-interop-that-people-actually-use/357" rel="noopener noreferrer"&gt;Part 2&lt;/a&gt;&lt;/strong&gt; will cover how to actually build interop that people use—keeping architecture simple, designing for humans, and avoiding the complexity traps that create technical debt.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://interop.io/professional-services/" rel="noopener noreferrer"&gt;Let us know&lt;/a&gt;&lt;/strong&gt; if you’re interested in discussing real-world use cases and dive deeper in what we’ve seen working before (and what to avoid).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://community.interop.io/t/from-strategy-to-poc-setting-up-desktop-interop-that-actually-works/303" rel="noopener noreferrer"&gt;Read full topic&lt;/a&gt;&lt;/p&gt;

</description>
      <category>general</category>
    </item>
    <item>
      <title>io.Connect Data Sharing Comparison Cheatsheet</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Tue, 04 Nov 2025 13:00:57 +0000</pubDate>
      <link>https://dev.to/interopio/ioconnect-data-sharing-comparison-cheatsheet-2084</link>
      <guid>https://dev.to/interopio/ioconnect-data-sharing-comparison-cheatsheet-2084</guid>
      <description>&lt;p&gt;The io.Connect platform provides several ways for apps to communicate and share data, from simple broadcasts to request/response calls, user-driven context linking, and continuous streaming. Each option has its own model, scope, and persistence rules that work best in different use cases and scenarios.&lt;/p&gt;

&lt;p&gt;The table below is a cheat sheet that lines Interop Methods, Intents, Streams, Pub/Sub, Shared Contexts, Channels, Workspace Contexts,  and Window Context side-by-side. The goal isn’t to teach each one in depth, but to help compare them quickly and choose the right tool for your workflow. If you’re looking for full explanations and examples (like how Shared Contexts differ from Workspace Contexts, or how Channels give users control), see the dedicated pages in the docs.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Interop Methods&lt;/th&gt;
&lt;th&gt;Intents&lt;/th&gt;
&lt;th&gt;Streams&lt;/th&gt;
&lt;th&gt;Pub/Sub&lt;/th&gt;
&lt;th&gt;Shared Contexts&lt;/th&gt;
&lt;th&gt;Color Channels&lt;/th&gt;
&lt;th&gt;Workspace Contexts&lt;/th&gt;
&lt;th&gt;Window Context&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Communication Model&lt;/td&gt;
&lt;td&gt;Request-Response&lt;/td&gt;
&lt;td&gt;Request-Response&lt;/td&gt;
&lt;td&gt;Streaming&lt;/td&gt;
&lt;td&gt;Broadcast&lt;/td&gt;
&lt;td&gt;Broadcast&lt;/td&gt;
&lt;td&gt;Broadcast&lt;/td&gt;
&lt;td&gt;Broadcast&lt;/td&gt;
&lt;td&gt;Window-specific&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Publish Data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅ *              Based on Channel Restrictions&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌*            Not intended for dynamic interop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Read Data&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅*            Servers could restrict access to data&lt;/td&gt;
&lt;td&gt;✅*            Servers could restrict access to data&lt;/td&gt;
&lt;td&gt;✅*            Servers could restrict access to data&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅*            Based on Channel Restrictions&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌*            Not intended for dynamic interop&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Discovery&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;User Controlled&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅*            Users are responsible for resolving ambiguous Intents through the Intents   Resolver UI&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅*            Users assign Application Instances to Color Channels&lt;/td&gt;
&lt;td&gt;✅*            Users control the Workspace grouping of Windows&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Defined Statically&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅*            Intents could also be defined dynamically&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅*            Could be defined as part of a Workspace Layout&lt;/td&gt;
&lt;td&gt;✅*            Could be defined as part of a Global Layout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Global&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌*            By design, scoped to the Application Instances joined on the same Color   Channel&lt;/td&gt;
&lt;td&gt;❌*            By design, scoped to the Applications Instances within a Workspace&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Persistence Across Restarts&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅*            Data could be persisted as part of a Workspace Layout&lt;/td&gt;
&lt;td&gt;✅*            Data could be persisted as part of a Global Layout&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Persistent (remains available if the server disconnects)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅*            The Workspaces Application could automatically destroy a Workspace Context   when the Workspace is closed, based on configuration&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Reannouncement (e.g., after a machine state change)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Caller/Updater Identification&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;One-to-One or Many&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;One-to-many&lt;/td&gt;
&lt;td&gt;One-to-one&lt;/td&gt;
&lt;td&gt;One-to-many&lt;/td&gt;
&lt;td&gt;One-to-many&lt;/td&gt;
&lt;td&gt;One-to-many&lt;/td&gt;
&lt;td&gt;One-to-many&lt;/td&gt;
&lt;td&gt;One-to-many&lt;/td&gt;
&lt;td&gt;One-to-one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Instance Launch Capability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅*            Can launch new Instances of Applications, if needed&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅*            Can be provided as an initial context by the launching Application Instance   via the AppManager API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;io.Connect API&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;methods()&lt;/code&gt;      &lt;code&gt;register()&lt;/code&gt;      &lt;code&gt;invoke()&lt;/code&gt;      &lt;code&gt;unregister()&lt;/code&gt;      …&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;all()&lt;/code&gt;            &lt;br&gt;&lt;code&gt;register()&lt;/code&gt;      &lt;code&gt;raise()&lt;/code&gt;            &lt;br&gt;…&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;createStream()&lt;/code&gt;      &lt;code&gt;stream.push()&lt;/code&gt;      &lt;code&gt;subscribe()&lt;/code&gt;      &lt;code&gt;stream.close()&lt;/code&gt;      …&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;publish()&lt;/code&gt;      &lt;code&gt;subscribe()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;all()&lt;/code&gt;      &lt;br&gt;&lt;code&gt;set()&lt;/code&gt;      &lt;br&gt;&lt;code&gt;get()&lt;/code&gt;      &lt;code&gt;subscribe()&lt;/code&gt;      &lt;br&gt;…&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;all()&lt;/code&gt;      &lt;br&gt;&lt;code&gt;join()&lt;/code&gt;      &lt;code&gt;publish()&lt;/code&gt;      &lt;code&gt;subscribe()&lt;/code&gt;      &lt;br&gt;…&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;workspace.setContext()&lt;/code&gt;      &lt;code&gt;workspace.updateContext()&lt;/code&gt;      &lt;code&gt;workspace.getContext()&lt;/code&gt;      &lt;code&gt;workspace.onContextUpdated()&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;window.setContext()&lt;/code&gt;      &lt;code&gt;window.updateContext()&lt;/code&gt;      &lt;code&gt;window.getContext()&lt;/code&gt;      &lt;code&gt;window.onContextUpdated()&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Interception&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FDC3 API Mapping&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;Intents&lt;/td&gt;
&lt;td&gt;Private   Channels&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;App   Channels&lt;/td&gt;
&lt;td&gt;User   Channels&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;[details="For those who don't like tables (ChatGPT and Claude looking at you), click here"]&lt;/p&gt;

&lt;h3&gt;
  
  
  Interop Methods
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Has:&lt;/strong&gt; publish &amp;amp; read; request-response; discovery; global; one-to-many; caller/updater ID; reannouncement.&lt;br&gt;
&lt;strong&gt;Lacks:&lt;/strong&gt; user control, static definition, persistence across restarts, persistence if the server disconnects, instance launch, interception, FDC3 mapping.&lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; read access may be restricted by the server.&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;methods()&lt;/code&gt;, &lt;code&gt;register()&lt;/code&gt;, &lt;code&gt;invoke()&lt;/code&gt;, &lt;code&gt;unregister()&lt;/code&gt;, …&lt;br&gt;
&lt;strong&gt;Learn more:&lt;/strong&gt; &lt;br&gt;
&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/interop/javascript/index.html#method_registration" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/capabilities/data-sharing/interop/javascript/index.html#method_registration&lt;/a&gt; &lt;br&gt;
&lt;a href="https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#interop-methods-streams-service-reuse-and-data-feeds" rel="noopener noreferrer"&gt;https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#interop-methods-streams-service-reuse-and-data-feeds&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Intents
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Has:&lt;/strong&gt; raise &amp;amp; handle (publish/read); request-response; discovery; &lt;strong&gt;user-controlled&lt;/strong&gt; resolver UI when ambiguous; &lt;strong&gt;can be defined statically&lt;/strong&gt; (also supports dynamic); global; one-to-one at execution; caller/updater ID; reannouncement; &lt;strong&gt;can launch a new app instance&lt;/strong&gt;; &lt;strong&gt;interception supported&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;Lacks:&lt;/strong&gt; persistence across restarts, persistence if the server disconnects.&lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; read access may be restricted by the server.&lt;br&gt;
&lt;strong&gt;FDC3:&lt;/strong&gt; Intents.&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;all()&lt;/code&gt;, &lt;code&gt;register()&lt;/code&gt;, &lt;code&gt;raise()&lt;/code&gt;, …&lt;br&gt;
&lt;strong&gt;Learn more:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/intents/overview/index.html" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/capabilities/data-sharing/intents/overview/index.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#intents-allow-users-to-select-actions" rel="noopener noreferrer"&gt;https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#intents-allow-users-to-select-actions&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Streams
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Has:&lt;/strong&gt; publish (push) &amp;amp; read (subscribe); streaming; discovery; global; one-to-many; caller/updater ID; reannouncement.&lt;br&gt;
&lt;strong&gt;Lacks:&lt;/strong&gt; user control, static definition, persistence across restarts, persistence if the server disconnects, instance launch, interception.&lt;br&gt;
&lt;strong&gt;Note:&lt;/strong&gt; read access may be restricted by the server.&lt;br&gt;
&lt;strong&gt;FDC3:&lt;/strong&gt; Private Channels.&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;createStream()&lt;/code&gt;, &lt;code&gt;stream.push()&lt;/code&gt;, &lt;code&gt;subscribe()&lt;/code&gt;, &lt;code&gt;stream.close()&lt;/code&gt;, …&lt;br&gt;
&lt;strong&gt;Learn more:&lt;/strong&gt; &lt;br&gt;
&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/interop/javascript/index.html#streaming" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/capabilities/data-sharing/interop/javascript/index.html#streaming&lt;/a&gt;&lt;br&gt;
&lt;a href="https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#interop-methods-streams-service-reuse-and-data-feeds" rel="noopener noreferrer"&gt;https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#interop-methods-streams-service-reuse-and-data-feeds&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Window Context
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Has:&lt;/strong&gt; window-specific (not global); one-to-one; &lt;strong&gt;can be defined statically&lt;/strong&gt; in a Global Layout; &lt;strong&gt;can persist across restarts&lt;/strong&gt; via Global Layout; reannouncement; &lt;strong&gt;can be supplied as initial context when launching&lt;/strong&gt; via AppManager.&lt;br&gt;
&lt;strong&gt;Lacks:&lt;/strong&gt; dynamic publish/read (not meant for dynamic interop), discovery, user control, global scope, &lt;strong&gt;persistence if the server disconnects&lt;/strong&gt;, caller/updater ID, interception, FDC3 mapping.&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;window.setContext()&lt;/code&gt;, &lt;code&gt;window.updateContext()&lt;/code&gt;, &lt;code&gt;window.getContext()&lt;/code&gt;, &lt;code&gt;window.onContextUpdated()&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Learn more:&lt;/strong&gt; &lt;br&gt;
&lt;a href="https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.html#context" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.html#context&lt;/a&gt;&lt;br&gt;
&lt;a href="https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#window-context" rel="noopener noreferrer"&gt;https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#window-context&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Pub/Sub
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Has:&lt;/strong&gt; publish &amp;amp; read; broadcast; global scope; one-to-many; caller/updater ID.&lt;br&gt;
&lt;strong&gt;Lacks:&lt;/strong&gt; discovery, user control, static definition, persistence across restarts, persistence if the server disconnects, reannouncement, instance launch, interception, FDC3 mapping.&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;publish()&lt;/code&gt;, &lt;code&gt;subscribe()&lt;/code&gt;.&lt;br&gt;
&lt;strong&gt;Learn more:&lt;/strong&gt; &lt;br&gt;
&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/pub-sub/overview/index.html" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/capabilities/data-sharing/pub-sub/overview/index.html&lt;/a&gt;&lt;br&gt;
&lt;a href="https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#p-523-pubsub-8" rel="noopener noreferrer"&gt;https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#p-523-pubsub-8&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Shared Contexts
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Has:&lt;/strong&gt; publish &amp;amp; read; broadcast; discovery; global; one-to-many; caller/updater ID; reannouncement; &lt;strong&gt;persists if the server disconnects&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;Lacks:&lt;/strong&gt; user control, static definition, persistence across restarts, instance launch, interception.&lt;br&gt;
&lt;strong&gt;FDC3:&lt;/strong&gt; App Channels.&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;all()&lt;/code&gt;, &lt;code&gt;set()&lt;/code&gt;, &lt;code&gt;get()&lt;/code&gt;, &lt;code&gt;subscribe()&lt;/code&gt;, …&lt;br&gt;
&lt;strong&gt;Learn more:&lt;/strong&gt; &lt;br&gt;
&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/shared-contexts/overview/index.html" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/capabilities/data-sharing/shared-contexts/overview/index.html&lt;/a&gt; &lt;br&gt;
&lt;a href="https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#shared-contexts-programmatic-data-sharing" rel="noopener noreferrer"&gt;https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#shared-contexts-programmatic-data-sharing&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Color Channels
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Has:&lt;/strong&gt; publish &amp;amp; read &lt;strong&gt;(subject to channel restrictions)&lt;/strong&gt;; broadcast; discovery; &lt;strong&gt;user-controlled&lt;/strong&gt; (users assign app instances to channels); one-to-many; caller/updater ID; reannouncement; &lt;strong&gt;persists if the server disconnects&lt;/strong&gt;.&lt;br&gt;
&lt;strong&gt;Lacks:&lt;/strong&gt; global scope (channel-scoped), static definition, persistence across restarts, instance launch, interception.&lt;br&gt;
&lt;strong&gt;FDC3:&lt;/strong&gt; User Channels.&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;all()&lt;/code&gt;, &lt;code&gt;join()&lt;/code&gt;, &lt;code&gt;publish()&lt;/code&gt;, &lt;code&gt;subscribe()&lt;/code&gt;, …&lt;br&gt;
&lt;strong&gt;Learn more:&lt;/strong&gt; &lt;br&gt;
&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/channels/overview/index.html" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/capabilities/data-sharing/channels/overview/index.html&lt;/a&gt; &lt;br&gt;
&lt;a href="https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#channels-empowering-end-users" rel="noopener noreferrer"&gt;https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#channels-empowering-end-users&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Workspace Contexts
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Has:&lt;/strong&gt; publish &amp;amp; read; broadcast; discovery; &lt;strong&gt;user-controlled&lt;/strong&gt; via workspace grouping; &lt;strong&gt;can be defined statically&lt;/strong&gt; in a Workspace Layout; one-to-many; caller/updater ID; reannouncement; &lt;strong&gt;can persist across restarts when saved in a Workspace Layout&lt;/strong&gt;; &lt;strong&gt;persists if the server disconnects&lt;/strong&gt; (may auto-destroy on workspace close, depending on config).&lt;br&gt;
&lt;strong&gt;Lacks:&lt;/strong&gt; global scope (workspace-scoped), instance launch, interception, FDC3 mapping.&lt;br&gt;
&lt;strong&gt;API:&lt;/strong&gt; &lt;code&gt;workspace.setContext()&lt;/code&gt;, &lt;code&gt;workspace.updateContext()&lt;/code&gt;, &lt;code&gt;workspace.getContext()&lt;/code&gt;, &lt;code&gt;workspace.onContextUpdated()&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Learn more:&lt;/strong&gt; &lt;br&gt;
&lt;a href="https://docs.interop.io/desktop/capabilities/windows/workspaces/javascript/index.html#workspace_context" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/capabilities/windows/workspaces/javascript/index.html#workspace_context&lt;/a&gt;&lt;br&gt;
&lt;a href="https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#workspace-context-multi-tasking-without-confusion" rel="noopener noreferrer"&gt;https://community.interop.io/t/key-io-connect-integration-concepts-explained/255#workspace-context-multi-tasking-without-confusion&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;[/details]&lt;/p&gt;

&lt;p&gt;For a simple overview, check:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://community.interop.io/t/key-io-connect-integration-concepts-explained/255" rel="noopener noreferrer"&gt;Key io.Connect Integration Concepts Explained&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And for more details see the respective documentation pages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/pub-sub/overview/index.html" rel="noopener noreferrer"&gt;Pub/Sub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/shared-contexts/overview/index.html" rel="noopener noreferrer"&gt;Shared Contexts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/channels/overview/index.html" rel="noopener noreferrer"&gt;Color Channels&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.interop.io/desktop/capabilities/windows/workspaces/javascript/index.html#workspace_context" rel="noopener noreferrer"&gt;Workspace Contexts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/interop/javascript/index.html#method_registration" rel="noopener noreferrer"&gt;Interop Methods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/intents/overview/index.html" rel="noopener noreferrer"&gt;Intents&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.interop.io/desktop/capabilities/data-sharing/interop/javascript/index.html#streaming" rel="noopener noreferrer"&gt;Streams&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.interop.io/desktop/capabilities/windows/window-management/javascript/index.html#context" rel="noopener noreferrer"&gt;Window Context&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://community.interop.io/t/io-connect-data-sharing-comparison-cheatsheet/324" rel="noopener noreferrer"&gt;Read full topic&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ioconnectdesktop</category>
    </item>
    <item>
      <title>Salesforce - Lightning Locker and io.Connect platform connected components - Standalone</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Thu, 16 Oct 2025 09:04:56 +0000</pubDate>
      <link>https://dev.to/interopio/salesforce-lightning-locker-and-ioconnect-platform-connected-components-standalone-1mjp</link>
      <guid>https://dev.to/interopio/salesforce-lightning-locker-and-ioconnect-platform-connected-components-standalone-1mjp</guid>
      <description>&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;em&gt;Note that the following sections are relevant only for:&lt;/em&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;If you intend on using Salesforce within the io.Connect Platform (&lt;strong&gt;io.Connect Desktop&lt;/strong&gt; or &lt;strong&gt;io.Connect Browser&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;Salesforce sessions with active Lightning Locker (in Session Settings)&lt;/li&gt;
&lt;li&gt;the latest versions of the Salesforce Adapter (5.13 and later).
For details on the legacy versions (3.0 and 4.0), see the &lt;a href="//../../legacy-adapter/installation-and-configuration/index.html"&gt;Legacy Adapter&lt;/a&gt; section.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;As 'Lightning Locker' does not allow direct usage of components packaged in an external namespace you will need to use Lightning Message Service (&lt;a href="https://developer.salesforce.com/docs/component-library/bundle/lightning-message-service/documentation" rel="noopener noreferrer"&gt;LMS&lt;/a&gt;) to communicate with the io.Connect Platform. Thus, we provide free of charge an LMS middleware package and a Plugin-based template that could serve as a reference point for further development. For simplicity of this documentation we will not focus on structuring the component, if you want you could do so on your own. Note that such custom components can be used both in your Lightning Our apps, or from within the Salesforce platform (with certain limitations and requirements).&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;em&gt;Note that using Salesforce within the io.Connect Platform has the advantage of not having to attach an io.Connect Utility Bar component to your Lightning App and not having to provide additional package configuration after installation in order to enable interoperability. These steps, however, are required when &lt;a href="//../web-browser/index.html"&gt;using Salesforce in a web browser&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;p&gt;For the use of the &lt;code&gt;InteropConsumerMixin&lt;/code&gt; to make sense, Lightning Web Security must be disabled:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Log in to your Salesforce organization as an administrator.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Go to &lt;code&gt;Setup &amp;gt; Security &amp;gt; Session Settings&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Make sure that Lightning Web Security is disabled in the "Lightning Web Security" section.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;em&gt;If Lightning Web Security is already enabled, consider using the &lt;a href="//../lws/index.html"&gt;LWS&lt;/a&gt; approach instead.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;⚠️ &lt;em&gt;You will need to use &lt;code&gt;Tick42__lmsStandalone&lt;/code&gt; in one of your UtilityBars in the Lightning Applications.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Limitations
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The LMS-based approach is not yet evaluated and tested in Salesforce Classic applications.&lt;/li&gt;
&lt;li&gt;Currently, the LMS-based approach &lt;strong&gt;does not support streaming&lt;/strong&gt; and other more complex interop methods functionality.&lt;/li&gt;
&lt;li&gt;Due to the security restrictions imposed by Salesforce, it's impossible to embed the Salesforce platform in an &lt;code&gt;&amp;lt;iframe&amp;gt;&lt;/code&gt; in &lt;strong&gt;io.Connect Browser&lt;/strong&gt;. To avoid this limitation, you can use the &lt;code&gt;InteropConsumerMixin&lt;/code&gt; component in Lightning Out apps or Visualforce pages that run in &lt;strong&gt;io.Connect Browser&lt;/strong&gt; instead.&lt;/li&gt;
&lt;li&gt;If using more than one instance of the component in the same app, all interop-enabled LWCs will have the same application name. This means that you won't be able to register more than one event listener for the same type of event. To avoid this limitation, it's recommended to either use the &lt;code&gt;InteropConsumerMixin&lt;/code&gt; component with Plugins or in different Lightning Out apps instead.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Examples
&lt;/h2&gt;

&lt;p&gt;An example Lightning Application is available in the &lt;code&gt;LMS[T42]&lt;/code&gt; Salesforce package. To retrieve the package into your project, execute the following command using the Salesforce CLI vs your organization where you have installed the packages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sf project retrieve start --package-name "LMS[T42]"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Salesforce App Definition
&lt;/h2&gt;

&lt;p&gt;The following sections describe how to create app definitions for the Salesforce platform or for your Lightning Out apps depending on whether you are using the Salesforce Adapter with &lt;strong&gt;io.Connect Desktop&lt;/strong&gt; or with &lt;strong&gt;io.Connect Browser&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  io.Connect Desktop
&lt;/h3&gt;

&lt;p&gt;To be able to open Salesforce in io.Connect Windows or Workspaces in &lt;strong&gt;io.Connect Desktop&lt;/strong&gt;, you must provide a valid &lt;a href="//../../../../desktop/developers/configuration/application/index.html"&gt;app definition&lt;/a&gt; for it. Besides the standard required definition properties (&lt;code&gt;"name"&lt;/code&gt;, &lt;code&gt;"type"&lt;/code&gt;, and &lt;code&gt;"url"&lt;/code&gt;), it's also required to enable &lt;a href="//../../../../desktop/getting-started/how-to/interop-enable-your-apps/javascript/index.html#auto_injection"&gt;auto injection&lt;/a&gt; of the &lt;a href="https://www.npmjs.com/package/@interopio/desktop" rel="noopener noreferrer"&gt;&lt;code&gt;@interopio/desktop&lt;/code&gt;&lt;/a&gt; library and to configure the usage of preload scripts. Enabling auto injection is necessary because the &lt;code&gt;@interopio/desktop&lt;/code&gt; library provides the interoperability capabilities of the &lt;code&gt;InteropConsumerMixin&lt;/code&gt; component. The preload scripts configuration is necessary because it enables using the &lt;code&gt;InteropConsumerMixin&lt;/code&gt; component.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;em&gt;Note that the preload scripts configuration also allows you to enable the usage of a Utility Bar component. Using a Utility Bar component isn't necessary when Salesforce is running in **io.Connect Desktop&lt;/em&gt;&lt;em&gt;, but if you decide to use one, you must provide the respective preload script. For details on how to attach one of the available io.Connect Utility Bar components, see the &lt;a href="//../web-browser/index.html#configuration"&gt;Usage &amp;gt; Web Browser &amp;gt; Configuration&lt;/a&gt; section.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The following is an example configuration for defining the Salesforce platform as an io.Connect app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"salesforce"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"window"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Salesforce"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"details"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;URL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;pointing&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Salesforce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;organization.&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://your-salesforce-url.salesforce.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;required&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;usage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;preload&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;scripts.&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"security"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"webSecurity"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"allowRunningInsecureContent"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"allowedExternalURISchemes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;required&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;interoperability&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;library&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;usage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;production.&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"preloadScripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"scripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;preload&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;script&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;required&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;using&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`InteropConsumerMixin`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;component.&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"https://enterprise-demos.dev.interop.io/preload-scripts/salesforce-request-factory-from-platform.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;preload&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;script&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;only&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;necessary&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;want&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Utility&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;component&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;when&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Salesforce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;is&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;running&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;io.Connect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Desktop.&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"https://enterprise-demos.dev.interop.io/preload-scripts/salesforce-utility-bar.js"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"useBase64PreloadScripts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;injection&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`@interopio/desktop`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;library.&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"autoInjectAPI"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"enabled"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(default)&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;provide&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;initialization&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;your&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;component.&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;If&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;library&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;auto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;initialized&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;with&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;settings&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;(e.g.&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;won't&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;able&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;features&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;that&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;are&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;disabled&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;default&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;such&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Workspaces&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;API&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Search&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;API).&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"autoInit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"customProperties"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;this&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;you&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;want&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Salesforce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Add App"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;menu&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Workspace.&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;This&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;will&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;enable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;users&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;open&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Salesforce&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Workspaces.&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"includeInWorkspaces"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  io.Connect Browser
&lt;/h3&gt;

&lt;p&gt;To be able to open your Lightning Out apps in io.Connect Windows or Workspaces in &lt;strong&gt;io.Connect Browser&lt;/strong&gt;, you must provide a valid &lt;a href="//../../../../browser/capabilities/app-management/index.html#app_definitions"&gt;app definitions&lt;/a&gt; for them when &lt;a href="//../../../../browser/developers/browser-platform/setup/index.html#initialization"&gt;initializing&lt;/a&gt; your Main app.&lt;/p&gt;

&lt;p&gt;The following is an example configuration for defining a Lightning Out app as an io.Connect app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;IOBrowserPlatform&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@interopio/browser-platform&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;licenseKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;my-license-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;applications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;local&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;salesforce&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;window&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Salesforce&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;details&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// URL pointing to your Lightning Out app.&lt;/span&gt;
                    &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://example.com/your-lightning-out-app/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;customProperties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Use this if you want to add your app to the "Add App" menu in a Workspace.&lt;/span&gt;
                    &lt;span class="c1"&gt;// This will enable users to open the app in Workspaces.&lt;/span&gt;
                    &lt;span class="na"&gt;includeInWorkspaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;io&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nc"&gt;IOBrowserPlatform&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;p&gt;The following sections describe the &lt;code&gt;InteropConsumerMixin&lt;/code&gt; component API and provide examples on how to implement an interop-enabled LWC.&lt;/p&gt;

&lt;h3&gt;
  
  
  Component API
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;InteropConsumerMixin&lt;/code&gt; mixin provides a set of properties and methods that you can use to interop-enable your LWC.&lt;/p&gt;

&lt;p&gt;The mixin has the following methods that can be accessed via the &lt;code&gt;this&lt;/code&gt; object upon successful connection to the io.Connect framework:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Accepts&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;requestConnectionStatus()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use this method to request the current connection status. It sends an LMS message to the &lt;code&gt;lmsStandalone&lt;/code&gt; which will return &lt;code&gt;{isConnected}&lt;/code&gt; object as a response.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;executePlatformMessageCallback()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(string, boolean, object)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use this method to send a response to the &lt;code&gt;InteropConsumerMixin&lt;/code&gt; component about the result from the Interop method invocation. The component will relay the response to the calling app. Accepts three required arguments - the ID of the invocation (which can be extracted from event details), a Boolean value denoting whether the invocation &lt;code&gt;Promise&lt;/code&gt; should be resolved (&lt;code&gt;true&lt;/code&gt;) or rejected (&lt;code&gt;false&lt;/code&gt;), and the actual result from the method invocation to be passed to the calling app.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;registerMethod()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(string, string)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Can be used instead of the &lt;code&gt;connected-methods&lt;/code&gt; property to register Interop methods for handling DOM events. Accepts as required arguments the name of the Interop method and the name of the DOM event.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;triggerOutbound()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(object)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Invokes an Interop method registered by other interop-enabled apps. Accepts as a required argument an object with &lt;code&gt;method&lt;/code&gt; and &lt;code&gt;payload&lt;/code&gt; properties specifying the name of the Interop method to invoke and arguments for the invocation.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;unregisterMethod()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(string)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Unregisters an Interop method. Accepts as a required argument the name of the Interop method to unregister.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The mixin provides the following hooks:&lt;br&gt;
| Method | Arguments | Description |&lt;br&gt;
|--------|-----------|-------------|&lt;br&gt;
| &lt;code&gt;connectedCallback()&lt;/code&gt; | &lt;code&gt;()&lt;/code&gt; | Used by the LWC rendering engine when the LWC component is initialized. This implementation subscribes for the correct LMS channels. |&lt;br&gt;
| &lt;code&gt;renderedCallback()&lt;/code&gt; | &lt;code&gt;()&lt;/code&gt; | Used by the LWC rendering engine when the LWC component is rendered. This implementation requests a connection status. |&lt;br&gt;
| &lt;code&gt;disconnectedCallback()&lt;/code&gt; | &lt;code&gt;()&lt;/code&gt; | Used by the LWC rendering engine when the LWC component is disconnected from the DOM. This implementation requests a connection status. |&lt;br&gt;
| &lt;code&gt;handlePlatformMessage()&lt;/code&gt; | &lt;code&gt;(object)&lt;/code&gt; | Used when a registered method is called from outside LWC's SF-application. |&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;LMSPlugin&lt;/code&gt; class provides the following properties:&lt;br&gt;
| Property | Type | Description |&lt;br&gt;
|----------|------|------------|&lt;br&gt;
| &lt;code&gt;listenToAPI&lt;/code&gt; | String | Sets the interop API method to listen for, e.g., &lt;code&gt;"My.LMS.Test.Inbound.Method"&lt;/code&gt;. |&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;LMSPlugin&lt;/code&gt; class provides the following hooks:&lt;br&gt;
| Method | Arguments | Description |&lt;br&gt;
|--------|-----------|-------------|&lt;br&gt;
| &lt;code&gt;onConnected()&lt;/code&gt; | &lt;code&gt;()&lt;/code&gt; | Registers the dedicated API method. |&lt;br&gt;
| &lt;code&gt;handlePlatformMessage()&lt;/code&gt; | &lt;code&gt;(object)&lt;/code&gt; | Determine if this Plugin instance is registering the API method and forwards to onInbound() hook. |&lt;br&gt;
| &lt;code&gt;onInbound()&lt;/code&gt; | &lt;code&gt;(string, object, string)&lt;/code&gt; | Executes custom logic on inbound API call. Accepts three required arguments - the ID of the invocation &lt;code&gt;method&lt;/code&gt; (which can be extracted from event details), a serializable &lt;code&gt;payload&lt;/code&gt; object and a sting with the &lt;code&gt;callbackID&lt;/code&gt; of the the invocation &lt;code&gt;Promise&lt;/code&gt; |&lt;/p&gt;

&lt;p&gt;The example &lt;code&gt;myInteropEnabledLms&lt;/code&gt; component provides the following hooks:&lt;br&gt;
| Method | Arguments | Description |&lt;br&gt;
|--------|-----------|-------------|&lt;br&gt;
| &lt;code&gt;onConnected()&lt;/code&gt; | &lt;code&gt;()&lt;/code&gt; | Initializes the Plugin instances. |&lt;br&gt;
| &lt;code&gt;handlePlatformMessage()&lt;/code&gt; | &lt;code&gt;(object)&lt;/code&gt; | Extends the mixin's method and forwards to onInbound in the registering Plugin. |&lt;/p&gt;
&lt;h3&gt;
  
  
  Example Implementation
&lt;/h3&gt;

&lt;p&gt;To interop-enable your LWC, you must:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;create a standard LWC with XML, HTML, and JavaScript files;&lt;/li&gt;
&lt;li&gt;use the &lt;code&gt;InteropConsumerMixin&lt;/code&gt; mixin in your LWC's JavaScript file to add the required functionality to your LWC;&lt;/li&gt;
&lt;li&gt;to use &lt;code&gt;Tick42__lmsStandalone&lt;/code&gt; in your home or record page or for best experience in one of your UtilityBars in the Lightning Applications;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following examples demonstrate how to create an interop-enabled LWC that will be used in an &lt;strong&gt;io.Connect Desktop&lt;/strong&gt; platform. The component registers an Interop method that can be invoked by other interop-enabled apps, and also invokes an Interop method already registered by other interop-enabled apps.&lt;/p&gt;

&lt;p&gt;Example XML configuration for a LWC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;LightningComponentBundle&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://soap.sforce.com/2006/04/metadata"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;apiVersion&amp;gt;&lt;/span&gt;60.0&lt;span class="nt"&gt;&amp;lt;/apiVersion&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;isExposed&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/isExposed&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;description&amp;gt;&lt;/span&gt;This component demonstrates inbound and outbound interoperability between Salesforce and io.Connect apps.&lt;span class="nt"&gt;&amp;lt;/description&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;masterLabel&amp;gt;&lt;/span&gt;My LMS Interop-Enabled Component&lt;span class="nt"&gt;&amp;lt;/masterLabel&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;targets&amp;gt;&lt;/span&gt;
        &lt;span class="c"&gt;&amp;lt;!-- Salesforce pages targeted by the component. --&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;target&amp;gt;&lt;/span&gt;lightning__RecordPage&lt;span class="nt"&gt;&amp;lt;/target&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;target&amp;gt;&lt;/span&gt;lightning__AppPage&lt;span class="nt"&gt;&amp;lt;/target&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;target&amp;gt;&lt;/span&gt;lightning__HomePage&lt;span class="nt"&gt;&amp;lt;/target&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/targets&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/LightningComponentBundle&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;code&gt;myInteropEnabledLms.html&lt;/code&gt; structure of an interop-enabled LWC that uses the &lt;code&gt;InteropConsumerMixin&lt;/code&gt; mixin:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;template&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;lightning-card&lt;/span&gt; &lt;span class="na"&gt;title=&lt;/span&gt;&lt;span class="s"&gt;"My Interop-Enabled LMS Component"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"slds-p-horizontal_medium slds-p-bottom_small"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;div&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;
                    Active plugins: {pluginStack}
                &lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;state: {state}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
                &lt;span class="nt"&gt;&amp;lt;p&amp;gt;&lt;/span&gt;last received value: {lastReceived}&lt;span class="nt"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/lightning-card&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;/template&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;code&gt;myInteropEnabledLms.js&lt;/code&gt; implementation of an interop-enabled LWC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;LightningElement&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;track&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lwc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;LMSPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;ListenPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BroadcastPlugin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./plugins.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;InteropConsumerMixin&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./lmsMixin.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyInteropEnabledLms&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;InteropConsumerMixin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;LightningElement&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;pluginInstances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="nx"&gt;plugins&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;ListenPlugin&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;BroadcastPlugin&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;track&lt;/span&gt;
    &lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;lastReceived&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kd"&gt;get&lt;/span&gt; &lt;span class="nf"&gt;pluginStack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;cls&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// This is a simple check that the plugins are of the correct type&lt;/span&gt;
    &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt; &lt;span class="k"&gt;instanceof&lt;/span&gt; &lt;span class="nx"&gt;LMSPlugin&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`io.Connect: the plugin &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; must extend the &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;LMSPlugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; class!`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;plugin&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;prototype&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onConnected&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;function&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;io.Connect: Error configuring WorkspaceUtilityBar.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt; A Plugin Class must have an onConnected method!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


    &lt;span class="nx"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;isConnected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;handleConnectionStatusUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleConnectionStatusUpdate&lt;/span&gt;&lt;span class="p"&gt;({...&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isConnected&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ready&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;PluginClass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;PluginClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pluginInstances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;handlePlatformMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handlePlatformMessage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handlePlatformMessage&lt;/span&gt;&lt;span class="p"&gt;({...&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;plugins&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;}&lt;/span&gt;

        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pluginInstances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;lastValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handlePlatformMessage&lt;/span&gt;&lt;span class="p"&gt;({...&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastReceived&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// disconnectedCallback() {&lt;/span&gt;
    &lt;span class="c1"&gt;//     if (super.disconnectedCallback) super.disconnectedCallback();&lt;/span&gt;
    &lt;span class="c1"&gt;// }&lt;/span&gt;

    &lt;span class="c1"&gt;// connectedCallback() {&lt;/span&gt;
    &lt;span class="c1"&gt;//     if (super.connectedCallback) super.connectedCallback();&lt;/span&gt;
    &lt;span class="c1"&gt;// }&lt;/span&gt;

    &lt;span class="c1"&gt;// renderedCallback() {&lt;/span&gt;
    &lt;span class="c1"&gt;//     if (super.renderedCallback) super.renderedCallback();&lt;/span&gt;
    &lt;span class="c1"&gt;// }&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;code&gt;plugins.js&lt;/code&gt; implementation of an interop-enabled LWC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TEST_INBOUND_METHOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My.LMS.Test.Inbound.Method&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TEST_OUTBOUND_METHOD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;My.LMS.Test.Outbound.Method&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LMSPlugin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;listenToAPI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;registered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_io&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nf"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listenToAPI&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;registered&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;registered&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listenToAPI&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * @description handles interop incoming message from other connected component, i.e. 'T42.SF.Test.Inbound'
     * @param {Object} message - invocation message with:
     *  - {string} method - the name of the remote method to be executed in the connected component
     *  - {Object} payload - the payload to be passed to the remote method
     *  - {string} callbackID - the internal auto generated callback ID
     */&lt;/span&gt;
    &lt;span class="nf"&gt;handlePlatformMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listenToAPI&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listenToAPI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onInbound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * @description handles interop incoming message from other connected component, i.e. 'T42.SF.Test.Inbound'
     * @param {string} method - the name of the remote method to be executed in the connected component
     * @param {Object} payload - the payload to be passed to the remote method
     * @param {string} callbackID - the internal auto generated callback ID
     */&lt;/span&gt;
    &lt;span class="c1"&gt;// eslint-disable-next-line no-unused-vars&lt;/span&gt;
    &lt;span class="nf"&gt;onInbound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`ioConnect: platform message (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) received`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// it is @api in InteropConsumerMixin&lt;/span&gt;
    &lt;span class="nf"&gt;requestConnectionStatus&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestConnectionStatus&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// it is @api in InteropConsumerMixin&lt;/span&gt;
    &lt;span class="nf"&gt;executePlatformMessageCallback&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executePlatformMessageCallback&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// it is @api in InteropConsumerMixin&lt;/span&gt;
    &lt;span class="nf"&gt;triggerOutbound&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;triggerOutbound&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// it is @api in InteropConsumerMixin&lt;/span&gt;
    &lt;span class="nf"&gt;registerMethod&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;registerMethod&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="c1"&gt;// it is @api in InteropConsumerMixin&lt;/span&gt;
    &lt;span class="nf"&gt;unregisterMethod&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unregisterMethod&lt;/span&gt;&lt;span class="p"&gt;(...&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ListenPlugin&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;LMSPlugin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;listenToAPI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TEST_INBOUND_METHOD&lt;/span&gt;
    &lt;span class="nf"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`ioConnect: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * @description handles interop incoming message from other io-connected application, i.e. 'My.LMS.Test.Inbound.Method'
     * @param {string} method - the name of the remote method to be executed in the connected component
     * @param {Object} payload - the payload to be passed to the remote method
     * @param {string} callbackID - the internal auto generated callback ID
     */&lt;/span&gt;
    &lt;span class="nf"&gt;onInbound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listenToAPI&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Expected to receive (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listenToAPI&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) it's own registered method, but received &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// If `true`, the `lmsStandalone` component will resolve the invocation `Promise`.&lt;/span&gt;
        &lt;span class="c1"&gt;// If `false`, the `lmsStandalone` component will reject the invocation `Promise`.&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;isSuccessful&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="c1"&gt;// Result that will be returned from invoking the Interop method.&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;invocationResult&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;OK&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="c1"&gt;// Send a response to the `lmsStandalone` component.&lt;/span&gt;
        &lt;span class="c1"&gt;// The `lmsStandalone` component will relay the response to the calling app.&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;executePlatformMessageCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSuccessful&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;invocationResult&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`onInbound: data received: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;lastValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BroadcastPlugin&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;LMSPlugin&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onConnected&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`ioConnect: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Invoke an outbound Interop method.&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;triggerOutbound&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`onConnected: sending &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;TEST_OUTBOUND_METHOD&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;triggerOutbound&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Providing the name of the Interop method to invoke and arguments for the invocation.&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TEST_OUTBOUND_METHOD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;value&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="c1"&gt;// Invoke an outbound Interop method.&lt;/span&gt;
        &lt;span class="c1"&gt;// Alternatively, you can use the io.Connect API directly: this.io.interop.invoke(args.method, args.payload);&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;triggerOutbound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Example &lt;code&gt;lmsMixin.js&lt;/code&gt; implementation of an interop-enabled LWC:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// import {EnclosingUtilityId, getInfo, getUtilityInfo, open, minimize, updatePanel, updateUtility} from 'lightning/platformUtilityBarApi';&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;api&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lwc&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;APPLICATION_SCOPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createMessageContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;releaseMessageContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;unsubscribe&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;lightning/messageService&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CONNECTION_STATUS_UPDATE&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@salesforce/messageChannel/Tick42__ConnectionStatusUpdate__c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;CONNECTION_STATUS_REQUEST&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@salesforce/messageChannel/Tick42__ConnectionStatusUpdateRequest__c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PLATFORM_MESSAGE&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@salesforce/messageChannel/Tick42__PlatformMessage__c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PLATFORM_MESSAGE_CALLBACK&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@salesforce/messageChannel/Tick42__PlatformMessageCallback__c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PLATFORM_MESSAGE_REGISTER&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@salesforce/messageChannel/Tick42__PlatformMessageRegister__c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;PLATFORM_MESSAGE_UNREGISTER&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@salesforce/messageChannel/Tick42__PlatformMessageUnregister__c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;SALESFORCE_MESSAGE&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@salesforce/messageChannel/Tick42__SalesforceMessage__c&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;InteropConsumerMixin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Base&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;messageContext&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createMessageContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// LMS context&lt;/span&gt;
    &lt;span class="nx"&gt;subscriptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt; &lt;span class="c1"&gt;// the LMS subscriptions&lt;/span&gt;

    &lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connectedCallback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;subscribeToMessageChannels&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;subscribeToMessageChannels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;PLATFORM_MESSAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handlePlatformMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APPLICATION_SCOPE&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;));&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;subscribe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nx"&gt;CONNECTION_STATUS_UPDATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;handleConnectionStatusUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;scope&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;APPLICATION_SCOPE&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;));&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * @description handles interop incoming message from other connected component, i.e. 'T42.SF.Test.Inbound'
     * @param {Object} message - invocation message with:
     *  - {string} method - the name of the remote method to be executed in the connected component
     *  - {Object} payload - the payload to be passed to the remote method
     *  - {string} callbackID - the internal auto generated callback ID
     */&lt;/span&gt;
    &lt;span class="nf"&gt;handlePlatformMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`ioConnect: platform message (&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;) received`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;handleConnectionStatusUpdate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;isConnected&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;isConnected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isConnected&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;isConnected&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;unsubscribeFromMessageChannels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;unsubscribe&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;subscriptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;disconnectedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;disconnectedCallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;disconnectedCallback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unsubscribeFromMessageChannels&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nf"&gt;releaseMessageContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;renderedCallback&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Note: all @wire are executed before renderedCallback()&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderedCallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;renderedCallback&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;requestConnectionStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;
    &lt;span class="nf"&gt;requestConnectionStatus&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CONNECTION_STATUS_REQUEST&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * A Platform-call result callback
     * @param {String} callbackID the callback ID
     * @param {Boolean} isSuccess the state of result
     * @param {Object} payload the data to send to the callback
     */&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;
    &lt;span class="nf"&gt;executePlatformMessageCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;callbackID&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;isSuccess&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;boolean&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ioConnect: callbackID and status are required&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt; callbackID is an auto generated system ID for the Promise callbacks&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt; and status is a boolean where you need to program it&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;s value as true or false.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PLATFORM_MESSAGE_CALLBACK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;callbackID&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;isSuccess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * Sends a Platform message request
     * @param {Object} payload the data to send to the platform
     */&lt;/span&gt;
    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;
    &lt;span class="nf"&gt;triggerOutbound&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;SALESFORCE_MESSAGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{...&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;
    &lt;span class="nf"&gt;registerMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PLATFORM_MESSAGE_REGISTER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;api&lt;/span&gt;
    &lt;span class="nf"&gt;unregisterMethod&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;publish&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messageContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;PLATFORM_MESSAGE_UNREGISTER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



</description>
      <category>security</category>
      <category>architecture</category>
      <category>frontend</category>
      <category>api</category>
    </item>
    <item>
      <title>Understanding logs in io.Connect</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Thu, 16 Oct 2025 08:43:05 +0000</pubDate>
      <link>https://dev.to/interopio/understanding-logs-in-ioconnect-43e0</link>
      <guid>https://dev.to/interopio/understanding-logs-in-ioconnect-43e0</guid>
      <description>&lt;p&gt;People talk about flashy frameworks, IDEs, and now AI copilots as the ultimate tools for developers. But I think logs hide real superpowers that we often overlook. They’re like truth serum you give to your apps, and they will reveal their secrets. Because they track every action, error, and alert, digging into logs can save you from embarrassing bugs and help you catch issues before they crush end-users’ systems.&lt;/p&gt;

&lt;p&gt;Logs provide valuable insights into a program’s activities. Typically, logs offer various severity levels, ranging from detailed step-by-step records to general overviews of the software’s execution during log generation. This data aids us in analyzing software, performance, and security issues. It is important to note that log files rarely provide the exact reason for an issue in plain text. Instead, log analysis is used to understand and diagnose problems by reconstructing events.&lt;/p&gt;

&lt;p&gt;There are multiple types of logs and storage locations. We will focus on application-type logs stored locally or locally like, meaning without the use of a dedicated logging system or log management software.&lt;/p&gt;

&lt;h2&gt;
  
  
  How are the log files structured in io.Connect?
&lt;/h2&gt;

&lt;p&gt;We use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;log4js for our JavaScript-based code&lt;/li&gt;
&lt;li&gt;log4net for our .NET components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;log4js&lt;/strong&gt; is a powerful logging library for Node.js, based on the Java log4j framework. It supports various flexible and configurable log levels and appenders.&lt;/p&gt;

&lt;p&gt;The log4js library offers flexibility because its behavior and settings are controlled through JSON configuration files (rather than being hardcoded). We use file and console-type appenders, but you can also use various custom appenders (learn how here &lt;a href="https://docs.interop.io/desktop/developers/configuration/system/index.html#logging-custom_log_appenders" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/developers/configuration/system/index.html#logging-custom_log_appenders&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Additionally log4js allows log message formatting and filtering.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;log4js&lt;/strong&gt; appenders:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;Appender Type&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Description&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;Use Case&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;File Appenders&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Writes logs to files on the disk.&lt;/td&gt;
&lt;td&gt;Primary appender in io.Connect Desktop.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Console Appenders&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Writes logs to the console.&lt;/td&gt;
&lt;td&gt;Useful for debugging and development.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;FTP Appenders&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Writes logs to a remote FTP server.&lt;/td&gt;
&lt;td&gt;Useful for centralized logging.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;log4js&lt;/strong&gt; log levels:&lt;/p&gt;

&lt;p&gt;A log level is the severity or priority of a log event (debug, info, etc). Whether an appender will see the event or not is determined by the layout.&lt;/p&gt;

&lt;p&gt;We use the following layout:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Format Example&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;[&amp;lt;DATE&amp;gt;] [&amp;lt;LEVEL&amp;gt;] [&amp;lt;COMPONENT&amp;gt;] - [&amp;lt;MESSAGE&amp;gt;]&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;DATE:&lt;/strong&gt; The timestamp of the log entry. Provides the context of when the event occurred.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;LEVEL:&lt;/strong&gt; The severity level of the log entry (e.g., DEBUG, INFO, WARN, ERROR, FATAL). Indicates the importance and urgency of the message.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;COMPONENT:&lt;/strong&gt; The part of the application generating the log.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MESSAGE:&lt;/strong&gt; The actual log message. Describes the event or error being logged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;Note: *&lt;/em&gt;.NET** logs also include &lt;code&gt;[&amp;lt;THREAD-ID&amp;gt;]&lt;/code&gt;.*&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Defaults settings&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log files roll over when they reach a certain size (10MB in io.cd case).&lt;/li&gt;
&lt;li&gt;A maximum of N rolled-over log files are kept (5 in io.cd case).&lt;/li&gt;
&lt;li&gt;Oldest log files are deleted when the limit is reached.&lt;/li&gt;
&lt;li&gt;Can be configured via %LocalAppData%\interop.io\io.Connect Desktop\Desktop\config\logger.json&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Important:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Interop.io does not log sensitive data. We only log what the software is executing.&lt;/li&gt;
&lt;li&gt;The timestamps in the log file reflect the time of the machine on which the application is running.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Tools for Log Analysis
&lt;/h2&gt;

&lt;p&gt;Logs are formatted to be compatible with simple text editors like Notepad, as well as more complex solutions like Splunk, and everything in between, depending on your choice. As a bare minimum, we recommend using Notepad++ for log analysis and working with .json files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Basic editors: Notepad, Notepad++, JSON formatters&lt;/li&gt;
&lt;li&gt;Advanced: Splunk, Graylog, Datadog, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Log Files Overview
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Application log
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;application.log&lt;/strong&gt; file is the main log generated by the Electron application, which drives the logic, applications, windows, layouts, etc, for io.Connect Desktop. This file should usually be the starting point in the analysis process.&lt;/p&gt;

&lt;p&gt;Default location: &lt;strong&gt;&lt;code&gt;%LocalAppData%\interop.io\io.Connect Desktop\UserData\&amp;lt;ENV&amp;gt;-&amp;lt;REG&amp;gt;\logs&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;ENV&amp;gt;-&amp;lt;REG&amp;gt;&lt;/code&gt; - represents the environment and region of io.Connect Desktop (e.g., DEMO-INTEROP.IO)&lt;/p&gt;

&lt;h3&gt;
  
  
  Bridge log
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;bridge.log&lt;/strong&gt; file is the log file of the .NET component in io.Desktop, responsible for the logic behind the windows (not to be confused with the OS).&lt;/p&gt;

&lt;p&gt;Default location: &lt;strong&gt;&lt;code&gt;%LocalAppData%\interop.io\io.Connect Desktop\UserData\&amp;lt;ENV&amp;gt;-&amp;lt;REG&amp;gt;\log&lt;/code&gt;s&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Gilding log
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;gilding.log&lt;/strong&gt; file is generated by &lt;strong&gt;gilding.exe&lt;/strong&gt;, a tiny .NET application used for starting and tracking the lifetime of the main io Application. This way &lt;strong&gt;gilding.exe&lt;/strong&gt; can collect logs in case the main .exe crashes.&lt;/p&gt;

&lt;p&gt;Default location: &lt;strong&gt;&lt;code&gt;%LocalAppData%\interop.io\io.Connect Desktop\UserData\&amp;lt;ENV&amp;gt;-&amp;lt;REG&amp;gt;\logs&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Getway log
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;gw.log&lt;/strong&gt; file logs the activities of the message bus of io.Connect Desktop. In the current version, it is written in &lt;strong&gt;Node.js&lt;/strong&gt; (was written in Java in the past).&lt;/p&gt;

&lt;p&gt;Default location: &lt;strong&gt;&lt;code&gt;%LocalAppData%\interop.io\io.Connect Desktop\UserData\&amp;lt;ENV&amp;gt;-&amp;lt;REG&amp;gt;\logs&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Installer log
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;installer.log&lt;/strong&gt; file is created by io.Connect Desktop during installation.&lt;/p&gt;

&lt;p&gt;Default location: &lt;strong&gt;%&lt;code&gt;LocalAppData%\interop.io\io.Connect Desktop\Installer&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Adapter logs
&lt;/h3&gt;

&lt;p&gt;The adapters logs are generated by the various adapters, like Outlook, Word, Excel, etc.&lt;/p&gt;

&lt;p&gt;Default location: &lt;strong&gt;&lt;code&gt;%LocalAppData%\interop.io\io.Connect Desktop\UserData\ApplicationAdapters&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Application-specific logs
&lt;/h3&gt;

&lt;p&gt;The application-specific logs are written by the applications participating in the io.Connect Desktop. You can use the API-s to log messages.&lt;/p&gt;

&lt;p&gt;Default location: &lt;strong&gt;&lt;code&gt;%LocalAppData%\interop.io\io.Connect Desktop\UserData\&amp;lt;ENV&amp;gt;-&amp;lt;REG&amp;gt;\logs\applications&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;em&gt;Important: application-specific logs are not to be confused with the Electron application.log.&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu1n9kd3e7ofa4fp2b0d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fgu1n9kd3e7ofa4fp2b0d.png" alt="Example of application logs|690x185" width="800" height="214"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;From &lt;strong&gt;9.9&lt;/strong&gt; onward you can funnel a web app’s own uncaught errors, console messages and failed network requests into the shared &lt;strong&gt;application.log&lt;/strong&gt; (under &lt;strong&gt;&lt;code&gt;&amp;lt;installation_location&amp;gt;/interop.io/io.Connect Desktop/UserData/&amp;lt;ENV&amp;gt;-&amp;lt;REG&amp;gt;/logs&lt;/code&gt;&lt;/strong&gt;) so frontend events sit in the same timeline as platform activity.&lt;/p&gt;

&lt;p&gt;Learn how to enable and configure it here - &lt;a href="https://docs.interop.io/desktop/capabilities/more/apis/index.html#logging-capturing_client_app_errors" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/capabilities/more/apis/index.html#logging-capturing_client_app_errors&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Extra: Crash reports
&lt;/h3&gt;

&lt;p&gt;io.Connect Desktop can automatically capture &lt;strong&gt;crash dumps&lt;/strong&gt; whenever any of its processes crashes.&lt;/p&gt;

&lt;p&gt;Default location: &lt;strong&gt;&lt;code&gt;%LocalAppData%\interop.io\io.Connect Desktop\UserData\&amp;lt;ENV&amp;gt;-&amp;lt;REG&amp;gt;\logs\crashes&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The feature can be turned on by adding the crashReporter block to system.json:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "crashReporter": {
    "enabled": true,
    "companyName": "Your Company",
    "productName": "Your Product",
    "folderPath": "%LocalAppData%/interop.io/io.Connect Desktop/crashes",
    "output": {
      "type": "local"   // local | server | backtrace
    }
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Output types&lt;/strong&gt;
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Behaviour&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;local&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Writes .dmp files under /reports.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;server&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;POSTs the crash payload to the REST endpoint set by serverUrl. Use this to forward dumps to &lt;strong&gt;io.Manager&lt;/strong&gt; or a custom service.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;backtrace&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Sends the report to a Backtrace instance (supply backTraceConfig).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Example for sending dumps to io.Manager:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "crashReporter": {
    "output": {
      "type": "server",
      "serverUrl": "http://localhost:4356/api/crashes"
    }
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Dump‑file maintenance&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Add an optional dumps object under output to control retention:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "crashReporter": {
    "output": {
      "dumps": {
        "limit": 10,
        "deleteOnSent": true
      }
    }
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;limit&lt;/strong&gt; – maximum number of dump files kept between restarts.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;deleteOnSent&lt;/strong&gt; – remove a dump after successful upload instead of archiving to /sent.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Reviewing Log Files – Best Practices &amp;amp; Use cases
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Identify session boundaries and total number of runs.&lt;/li&gt;
&lt;li&gt;Confirm version and environment metadata.&lt;/li&gt;
&lt;li&gt;Review the full system configuration.&lt;/li&gt;
&lt;li&gt;Trace warnings/errors across log sets.&lt;/li&gt;
&lt;li&gt;Analyze each process from start to finish, across rolled-over logs if necessary.&lt;/li&gt;
&lt;li&gt;Identify the user environment.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  System log rotation
&lt;/h2&gt;

&lt;p&gt;Starting with &lt;strong&gt;io.Connect Desktop 9.3&lt;/strong&gt; you can tell the platform what to do with older logs on startup. The setting lives under logging.files in &lt;strong&gt;system.json&lt;/strong&gt; and lets you keep your log folder clean without scripting a clean‑up job.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;onStartup value&lt;/th&gt;
&lt;th&gt;Effect&lt;/th&gt;
&lt;th&gt;Good for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;keep (default)&lt;/td&gt;
&lt;td&gt;Leave yesterday’s files alone.&lt;/td&gt;
&lt;td&gt;Workstations where disk isn’t an issue.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;delete&lt;/td&gt;
&lt;td&gt;Remove the whole log folder before new session starts.&lt;/td&gt;
&lt;td&gt;Locked‑down VDI or demo pods.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;archive&lt;/td&gt;
&lt;td&gt;Move files to moveOldTo or default archive path.&lt;/td&gt;
&lt;td&gt;Debugging long‑running issues across days.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;See how to configure it here: &lt;a href="https://docs.interop.io/desktop/developers/configuration/system/index.html#logging-system_logs-log_files" rel="noopener noreferrer"&gt;https://docs.interop.io/desktop/developers/configuration/system/index.html#logging-system_logs-log_files&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the next article, we’ll share some use cases and frequently used keywords that can help find useful information.&lt;/p&gt;

</description>
      <category>security</category>
      <category>monitoring</category>
      <category>devops</category>
      <category>performance</category>
    </item>
    <item>
      <title>Examining logs in practice</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Thu, 16 Oct 2025 08:35:07 +0000</pubDate>
      <link>https://dev.to/interopio/examining-logs-in-practice-49of</link>
      <guid>https://dev.to/interopio/examining-logs-in-practice-49of</guid>
      <description>&lt;p&gt;In a previous article (&lt;a href="https://community.interop.io/t/understanding-logs-in-io-connect/36/1" rel="noopener noreferrer"&gt;https://community.interop.io/t/understanding-logs-in-io-connect/36/1&lt;/a&gt;) we  covered some logs io.Connect stores and how to configure them based on our needs and context. In this article we'll go through some sample use cases and common scenarios, and show where to look to find the root cause.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to identify the start of a run
&lt;/h2&gt;

&lt;p&gt;To identify the version of the component and how many runs you have in the log file, search for the string "&lt;strong&gt;===== "&lt;/strong&gt; (5 equal symbols and an empty space) in &lt;strong&gt;application.log&lt;/strong&gt;. Each run will begin with logging the mentioned string. In the example below you can see GlueDesktop being started 6 times over the reviewed log - you have 6 different hits searching with "&lt;strong&gt;=====&lt;/strong&gt; ". Note that if you omit the empty space at the end of the search string, you need to divide the result by 2 since the equal sign string is used twice on each line:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3awicdq1f4nl52z69z6n.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3awicdq1f4nl52z69z6n.jpeg" alt="image|690x104" width="800" height="504"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check components versions and Environment &amp;amp; Region
&lt;/h2&gt;

&lt;p&gt;Right under the io.Connect Desktop version, you can see other details such as the user environment, host OS settings, system configuration, all versions of the different components comprising the io.Connect Desktop, and the command line used to start the inner .exe. This is useful because sometimes there are extra parameters here that could explain certain behaviors.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ze33kjns1ngurgqdo73.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5ze33kjns1ngurgqdo73.png" alt="image|690x104" width="800" height="120"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here is an example of the components visualized in a .json format:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3900rafrp8gdmuqdpax.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu3900rafrp8gdmuqdpax.jpeg" alt="image|262x500" width="467" height="891"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Check which version of the components you are reviewing.&lt;/strong&gt; Sometimes, the resolution is in a newer version.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check the full system configuration
&lt;/h2&gt;

&lt;p&gt;Search for the “&lt;strong&gt;full system config&lt;/strong&gt;” string to find the system configuration. The data is in .json format and can be additionally formatted for easier reading. As mentioned, issues can stem solely from configuration. Keep in mind that the io.Connect Desktop configuration can be locally based or fetched from a remote server during your analysis.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7cit6bbp4sox4f9mk67p.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7cit6bbp4sox4f9mk67p.jpeg" alt="image|690x116" width="800" height="134"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check running application list
&lt;/h2&gt;

&lt;p&gt;To see a running app list, search with the string ‘&lt;strong&gt;app-mgr - app list&lt;/strong&gt;’. Note that this list will change over time, as not all applications are loaded at startup - some are initiated by user clicks or intents from other applications as part of a workflow.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flroaoj3nfn3uac2z1l5w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flroaoj3nfn3uac2z1l5w.png" alt="image|690x51" width="800" height="59"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check all auto started applications
&lt;/h2&gt;

&lt;p&gt;To search for all applications that are auto-start configured, search for the “&lt;strong&gt;auto-start-apps&lt;/strong&gt;” string:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbrghj7k9ln6yb8ykn2yj.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbrghj7k9ln6yb8ykn2yj.jpeg" alt="image|690x94" width="800" height="109"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check the life cycle of a specific application
&lt;/h2&gt;

&lt;p&gt;To see all starts of a particular application you are interested in, use the string "&lt;strong&gt;app  - starting&lt;/strong&gt;".&lt;br&gt;
This is used not only to check whether an application started (or attempted to), but also to track the full lifetime of the app. A token (eqyKWn3I3g in the screenshot below) will be created for each start, which can later be used to track the application in the bridge.log file. This allows you to cross-check between different log files.&lt;/p&gt;

&lt;p&gt;Using the same approach, you can also see and obtain the window ID(15380_2 in the screenshot below), which you can use to track the lifetime of the app window.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpo133mblz63k4c9sot9y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpo133mblz63k4c9sot9y.png" alt="image|690x76" width="800" height="88"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to track layout restoration
&lt;/h2&gt;

&lt;p&gt;To track the layout restoration, search for “&lt;strong&gt;restoring layout name&lt;/strong&gt;”. You can copy and explore the restore options and the full layout definition. You can also get the token from the layout/manager call and track the restore operation. In the screenshot below, the token is [Hde_9GOUn2]. To check the completion event, search for “restore successful, duration:”&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkx1ze611t3zckkfar1p.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvkx1ze611t3zckkfar1p.jpeg" alt="image|690x122" width="800" height="141"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How to track workspace restoration
&lt;/h2&gt;

&lt;p&gt;To track workspace restoration, search for “&lt;strong&gt;Received control operation openWorkspace&lt;/strong&gt;”&lt;/p&gt;

&lt;p&gt;If no frame is available -&amp;gt; “&lt;strong&gt;Creating new frame for workspace&lt;/strong&gt;”&lt;/p&gt;

&lt;p&gt;If frame is available -&amp;gt; “&lt;strong&gt;Creating new workspace 4sXYbDX1g8 in frame 50736_sf_2&lt;/strong&gt;”&lt;/p&gt;

&lt;h2&gt;
  
  
  How to check Protocol handler usage
&lt;/h2&gt;

&lt;p&gt;The protocol handler is invoked when a URL is clicked in the browser, or a file is opened in the file explorer. It goes to &lt;strong&gt;gilding.exe&lt;/strong&gt;, which sends the request to the Electron main process via a pipe message. You can cross-check this &lt;strong&gt;in the gilding logs&lt;/strong&gt; and &lt;strong&gt;in the application log&lt;/strong&gt;.&lt;br&gt;
1.1 Gilding logs - look at the startup arguments. These startup arguments will be missing in the gilding logs if the protocol handler is invoked when the system is already running.&lt;br&gt;
1.2 Application logs - search for "&lt;strong&gt;pipe-manager&lt;/strong&gt;" and "&lt;strong&gt;protocol-handler&lt;/strong&gt;"&lt;/p&gt;

&lt;h2&gt;
  
  
  How to monitor CPU and memory usage
&lt;/h2&gt;

&lt;p&gt;To check CPU and memory usage, search for &lt;strong&gt;“perf-log&lt;/strong&gt;“ in the application log to see the total system CPU and memory usage and identify an application that might be consuming a suspicious number of resources.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovnkxw5cyy6ax8ilv5vt.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fovnkxw5cyy6ax8ilv5vt.jpeg" alt="image|690x167" width="800" height="193"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note that logging is evolving, and some logs might appear only in newer versions, or others can be changed or deprecated.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>monitoring</category>
      <category>tooling</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Answering Questions with io.Insights Metrics and Grafana</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Thu, 16 Oct 2025 08:32:49 +0000</pubDate>
      <link>https://dev.to/interopio/answering-questions-with-ioinsights-metrics-and-grafana-1jpn</link>
      <guid>https://dev.to/interopio/answering-questions-with-ioinsights-metrics-and-grafana-1jpn</guid>
      <description>&lt;p&gt;This tutorial shows how to use metrics information from io.Insights to answer questions about user and application behavior across your enterprise. It's a practical example of identifying the most frequently used applications in your io.Connect environment.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;What You'll Learn&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;io.Insights publishes a rich set of information about the platform and applications running in it that can be used to investigate both individual entities (specific applications, workspaces, users, layouts) as well as generate aggregated reports about behavior and usage patterns.&lt;/p&gt;

&lt;p&gt;When coupled with a querying system like Grafana, infrastructure and analytics teams can build dashboards, set up alerts, and run queries to gain visibility into a wide range of operational metrics.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Prerequisites&lt;/strong&gt;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;io.Insights enabled and configured in your io.Connect environment – see &lt;a href="https://docs.interop.io/insights/configuration/index.html" rel="noopener noreferrer"&gt;https://docs.interop.io/insights/configuration/index.html&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Grafana connected to your OpenTelemetry metrics collector – see &lt;a href="https://community.interop.io/t/getting-started-with-io-insights/55" rel="noopener noreferrer"&gt;https://community.interop.io/t/getting-started-with-io-insights/55&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Access to Grafana dashboard creation&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 1: Access Your Grafana Dashboard&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Navigate to your Grafana instance and access the Dashboards section. You should see your existing dashboards, including any io.Insights dashboards you may have already created.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwds4uoeg40opysv5dm61.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwds4uoeg40opysv5dm61.jpeg" alt="image|690x181" width="800" height="210"&gt;&lt;/a&gt;&lt;br&gt;
Click &lt;strong&gt;New&lt;/strong&gt; to create a new dashboard -&amp;gt; &lt;strong&gt;New Dashboard&lt;/strong&gt;, then select &lt;strong&gt;+ Add visualization&lt;/strong&gt; to begin building your metrics query.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrakmub3tq2clbeyw1my.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsrakmub3tq2clbeyw1my.png" alt="image|178x167" width="178" height="167"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 2: Create a New Visualization Panel&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;You'll start with a blank panel configuration. The key to this demonstration is using data from the app_started metric, which represents the number of times each application has been started during platform sessions.&lt;/p&gt;

&lt;p&gt;In the metrics selection dropdown, you'll see various io.Insights metrics available, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;app_started_total&lt;/code&gt; - our target metric&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app_duration_*&lt;/code&gt; - application focus time metrics&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;app_memory_*&lt;/code&gt; - memory usage metrics&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;platform_startup_*&lt;/code&gt; - platform initialization metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Select &lt;code&gt;app_started_total&lt;/code&gt; as your primary metric.&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2hb7z9ys6ns2yob8ssp.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc2hb7z9ys6ns2yob8ssp.jpeg" alt="image|690x346" width="800" height="402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 3: Switch to Bar Chart Visualization&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;For displaying top applications by usage count, a bar chart provides clearer insights than a time series. Change your visualization type to &lt;strong&gt;Bar gauge&lt;/strong&gt; in the panel options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ew9t5jgfmbn1lfxn1al.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ew9t5jgfmbn1lfxn1al.jpeg" alt="image|690x326" width="800" height="378"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This creates a much more readable view showing each application and its relative usage frequency.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 4: Configure the Query and Aggregation&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Since we want to identify the most-used applications based on total startup counts, we need to apply aggregation. The app_started metric is an increasing counter, so we're interested in the maximum value it reaches for each application.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fghx0kit9dj7fn1j3deh1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fghx0kit9dj7fn1j3deh1.jpeg" alt="image|690x272" width="800" height="315"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Configure your query settings:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Metric&lt;/strong&gt;: app_started_total&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Aggregation&lt;/strong&gt;: Select &lt;strong&gt;Max over time&lt;/strong&gt; since we want the total count per application&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuk9jhi7tnseiwdddkqm5.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuk9jhi7tnseiwdddkqm5.jpeg" alt="image|622x472" width="622" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Group by&lt;/strong&gt;: Application name (this will separate results by individual applications). &lt;strong&gt;Aggregations&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Max by&lt;/strong&gt; -&amp;gt; &lt;strong&gt;application&lt;/strong&gt; -&amp;gt; &lt;strong&gt;instance&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sum&lt;/strong&gt;: get total runs per applications
3.&lt;em&gt;gregations&lt;/em&gt;* -&amp;gt; &lt;strong&gt;Sum&lt;/strong&gt; -&amp;gt; &lt;strong&gt;by label&lt;/strong&gt; -&amp;gt; &lt;strong&gt;application&lt;/strong&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbsogkbzgk1jwsud11w1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftbsogkbzgk1jwsud11w1.png" alt="image|408x303" width="408" height="303"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Run queries&lt;/strong&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 5: Add Data Transformations&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;To make the data more presentable and show only the top results, we'll add transformations. Click on the &lt;strong&gt;Transformations&lt;/strong&gt; tab to access additional data processing options.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6xtpwsrinu1n7qt8uuui.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6xtpwsrinu1n7qt8uuui.jpeg" alt="image|690x407" width="800" height="472"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The transformations allow you to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Limit results&lt;/strong&gt;: Show only the top N applications&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sort data&lt;/strong&gt;: Order by usage count (descending)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rename fields&lt;/strong&gt;: Clean up display names&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Calculate values&lt;/strong&gt;: Perform additional aggregations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Group by nested tables&lt;/strong&gt;: If you want to organize by additional attributes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This ensures you're displaying the most actionable data and the applications that are actually being used most frequently by your users..&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiolbvclb2k1shw2p9nr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffiolbvclb2k1shw2p9nr.png" alt="image|690x330" width="800" height="383"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Step 6: Review Your Results&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Your final visualization should clearly show which io.Connect applications are used most frequently in your environment. This information can help you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Identify popular applications&lt;/strong&gt; for optimization or additional investment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Spot underutilized applications&lt;/strong&gt; that may need better promotion or could be candidates for removal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Plan infrastructure capacity&lt;/strong&gt; based on actual usage patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make data-driven decisions&lt;/strong&gt; about application portfolio management&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Beyond This Example&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;This demonstration shows just a simple example of extracting metrics information in a few clicks. Experienced analysts can build extremely sophisticated dashboards that include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Regional breakdowns&lt;/strong&gt;: Most used applications per geographic region&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version analysis&lt;/strong&gt;: Usage patterns across different application versions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Time-based trends&lt;/strong&gt;: Usage changes over specific periods&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;User behavior analysis&lt;/strong&gt;: Individual user application preferences&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance correlations&lt;/strong&gt;: Connecting usage data with performance metrics&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Key Insights from io.Insights Data&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;All the telemetry information published by io.Insights describes events that occur in your applications and platform. This data can optionally be exported as metrics, giving you instant visibility into any aspect of your application usage related to the features of the io.Connect platform.&lt;/p&gt;

&lt;p&gt;The app_started metric used in this example is just one of many available metrics. Other valuable metrics include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;app_duration: The time an app has been on focus during each platform session.&lt;/li&gt;
&lt;li&gt;app_error: The number of times an app error was received during each platform session.&lt;/li&gt;
&lt;li&gt;workspace_stopped: The number of times a Workspace has been stopped during each platform session.&lt;/li&gt;
&lt;li&gt;system_cpu and system_memory: Resource utilization patterns&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Next Steps&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;From this foundation, you can:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Save the query&lt;/strong&gt; for future use and monitoring&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up alerts&lt;/strong&gt; when usage patterns change significantly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Add the panel to a dashboard&lt;/strong&gt; with other related metrics&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create additional breakdowns&lt;/strong&gt; by user, time period, or platform version&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Export data&lt;/strong&gt; for further analysis in other tools&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach transforms raw telemetry data into actionable business intelligence, helping you optimize your io.Connect deployment based on real user behavior.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Useful links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.interop.io/insights" rel="noopener noreferrer"&gt;&lt;strong&gt;io.Insights Documentation&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://community.interop.io/t/getting-started-with-io-insights/55" rel="noopener noreferrer"&gt;https://community.interop.io/t/getting-started-with-io-insights/55&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://community.interop.io/t/track-down-issues-fast-with-io-insights/9" rel="noopener noreferrer"&gt;https://community.interop.io/t/track-down-issues-fast-with-io-insights/9&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>analytics</category>
      <category>monitoring</category>
      <category>tutorial</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Track down issues fast with io.Insights</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Thu, 16 Oct 2025 08:31:54 +0000</pubDate>
      <link>https://dev.to/interopio/track-down-issues-fast-with-ioinsights-3c2n</link>
      <guid>https://dev.to/interopio/track-down-issues-fast-with-ioinsights-3c2n</guid>
      <description>&lt;p&gt;Working in finance requires quick and precise identification of problems. In this article, we’ll walk through how to leverage io.Insights to utilize io.Connect telemetry data, specifically tracing and logging, to swiftly identify application issues.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario Overview
&lt;/h3&gt;

&lt;p&gt;We have two interconnected applications:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Client List&lt;/strong&gt;: Displays client information fetched from a backend, allowing user selection.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Portfolio Viewer&lt;/strong&gt;: Subscribes to selection changes from the Client List, fetching and displaying detailed portfolio data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu20cbd7ltpbk0dv2aehz.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu20cbd7ltpbk0dv2aehz.jpeg" alt="image|690x443" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The synchronization has stopped for a specific user, and we want to quickly trace and pinpoint the issue. We’ll be using io.Insights to collect and pass all data and Grafana as an example platform for exploration and analysis. Any alternative of Grafana can be used in a similar way.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step-by-Step Diagnostic Process
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1. Enable Observability
&lt;/h4&gt;

&lt;p&gt;Before digging into the data we need to make sure io.Insights is enabled. This is done simply by adding the &lt;code&gt;"insights"&lt;/code&gt; (&lt;strong&gt;pre 10.0 versions&lt;/strong&gt; use &lt;code&gt;"otel"&lt;/code&gt;)1 top-level key in the system.json system configuration file of io.Connect Desktop located in the %LocalAppData%/interop.io/io.Connect Desktop/Desktop/config or by using the otel property of the configuration object when &lt;a href="https://docs.interop.io/browser/developers/browser-platform/setup/index.html" rel="noopener noreferrer"&gt;initializing your Main app&lt;/a&gt; in io.Connect Browser, and specifying the publishing URL of the OTEL collector.&lt;/p&gt;

&lt;p&gt;See the documentation about configuration here - &lt;a href="https://docs.interop.io/insights/configuration/index.html#ioconnect_desktop" rel="noopener noreferrer"&gt;https://docs.interop.io/insights/configuration/index.html#ioconnect_desktop&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;1 The &lt;code&gt;"insights"&lt;/code&gt; top level object is used to enable and configure io.Insights since &lt;strong&gt;version 10.0&lt;/strong&gt;. The &lt;code&gt;"otel"&lt;/code&gt; top level object is used to enable and configure io.Insights in &lt;strong&gt;versions pre-10.0.&lt;/strong&gt; Don’t worry - it’s &lt;strong&gt;backward compatible&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Having io.Insights enabled will now expose tracing and log events for our platform. Next, head to the &lt;strong&gt;Traces&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;[&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbp5ke463xdmss0kfyfd1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbp5ke463xdmss0kfyfd1.png" alt="image|50%x50%" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Open the Query Interface
&lt;/h4&gt;

&lt;p&gt;Click the three-dot menu in the Traces panel and click &lt;strong&gt;Explore&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This brings up the TraceQL query builder. We can use this to filter the traces relevant to the issue.&lt;/p&gt;

&lt;p&gt;[&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbp5ke463xdmss0kfyfd1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbp5ke463xdmss0kfyfd1.png" alt="image|50%x50%" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Filter by User and Application
&lt;/h4&gt;

&lt;p&gt;Construct a query targeting the specific user and app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ span.user = "VelkoNikolov" &amp;amp;&amp;amp; span.tracingAppName = "ClientList" }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;[&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmotw4e7yclwedg4rjfe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxmotw4e7yclwedg4rjfe.png" alt="image|60%x60%" width="800" height="146"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And run the query to list out all traces related to that user. Under Service &amp;amp; Operations we can simply click the table row we are interested in to drill down into more details.&lt;/p&gt;

&lt;p&gt;[&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qg16faihbxbmtubnm1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qg16faihbxbmtubnm1b.png" alt="image|60%x60%" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  4. Inspect the Trace Tree
&lt;/h4&gt;

&lt;p&gt;Click any trace row to view its hierarchical structure. Click &lt;code&gt;Span attributes&lt;/code&gt; to explore more,&lt;/p&gt;

&lt;p&gt;Each span represents a sub-operation. At the top, you’ll typically see a span from &lt;code&gt;ClientList&lt;/code&gt;, representing the update. Keep clicking downward through the spans to trace the flow.&lt;/p&gt;

&lt;p&gt;[&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qg16faihbxbmtubnm1b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4qg16faihbxbmtubnm1b.png" alt="image|60%x60%" width="800" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  5. Spot the Failing Span
&lt;/h4&gt;

&lt;p&gt;One of the spans will have an error event. Click it and check the &lt;strong&gt;Events&lt;/strong&gt; tab.&lt;/p&gt;

&lt;p&gt;The exception message shows: &lt;code&gt;"Failed to retrieve portfolio"&lt;/code&gt;, indicating that the problem lies somewhere in the retrieval of the portfolio from the back-end service. So now we know where things are going wrong.&lt;/p&gt;

&lt;p&gt;[&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F910fbfcfcy73g6kaqo23.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F910fbfcfcy73g6kaqo23.png" alt="image|60%x60%" width="800" height="191"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  6. Dig into Backend Request
&lt;/h4&gt;

&lt;p&gt;Since the back-end service also uses OTEL observability, we can dig deeper into its operation in the trace to find what the error was. Let’s scroll down to the backend service spans (e.g., &lt;code&gt;ClientsService&lt;/code&gt;) and open the request handler.&lt;/p&gt;

&lt;p&gt;Click &lt;strong&gt;Logs for this span&lt;/strong&gt; to open the log view.&lt;/p&gt;

&lt;p&gt;[&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3wq1jjv9dsrzjj7nfej.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe3wq1jjv9dsrzjj7nfej.png" alt="image|60%x60%" width="800" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  7. Analyze the Log Message
&lt;/h4&gt;

&lt;p&gt;Here, the log output makes it crystal clear:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;User VelkoNikolov does not have entitlement VIEW_EXTENDED_PORTFOLIO
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This explains the error entirely - the user doesn’t have the required access to see that data.&lt;/p&gt;

&lt;p&gt;[&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwlp7d8ubw099i6fgw5wl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwlp7d8ubw099i6fgw5wl.png" alt="image|60%x60%" width="800" height="488"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fixing the issue
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Let the entitlements team know what’s missing.&lt;/li&gt;
&lt;li&gt;Inform the user about the permission settings.&lt;/li&gt;
&lt;li&gt;Optionally, investigate entitlement assignment via further trace exploration.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So no ticket escalations and no guessing - finding a tricky problem took just few minutes. The out-of-the-box instruments provided by io.Connect + io.Insights gives you everything you need with minimum setup in the observability platform you are already familiar with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In the &lt;a href="https://community.interop.io/t/answering-questions-with-io-insights-metrics-and-grafana/153" rel="noopener noreferrer"&gt;next article&lt;/a&gt;, we’ll cover custom instruments and more advanced workflows across services.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Useful links&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.interop.io/insights" rel="noopener noreferrer"&gt;&lt;strong&gt;io.Insights Documentation&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://community.interop.io/t/getting-started-with-io-insights/55" rel="noopener noreferrer"&gt;https://community.interop.io/t/getting-started-with-io-insights/55&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://community.interop.io/t/answering-questions-with-io-insights-metrics-and-grafana/153" rel="noopener noreferrer"&gt;https://community.interop.io/t/answering-questions-with-io-insights-metrics-and-grafana/153&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Getting Started with io.Insights</title>
      <dc:creator>Toni Petov</dc:creator>
      <pubDate>Thu, 16 Oct 2025 08:27:07 +0000</pubDate>
      <link>https://dev.to/interopio/getting-started-with-ioinsights-9l5</link>
      <guid>https://dev.to/interopio/getting-started-with-ioinsights-9l5</guid>
      <description>&lt;p&gt;If you’re building apps or maintaining a platform running hundreds of apps across your enterprise, you might have run into a similar situation: something small breaks, performance tanks, or a user hits a weird and hard-to-reproduce bug. So you need to chase logs, check version mismatches, and guess at backend timings. Or you may just want to monitor and observe how your apps are doing inside the platform.&lt;/p&gt;

&lt;p&gt;That’s where io.Insights comes in, giving you observability into what’s actually happening inside the io.Connect platform, your apps, and everything running on top of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is io.Insights?
&lt;/h2&gt;

&lt;p&gt;Io.Insights is an observability extension built specifically for the io.Connect ecosystem. It captures telemetry (traces, metrics, and logs) from desktop or browser-based apps, APIs, io.Manager, and the platform itself. And it does this with very little extra setup required.&lt;/p&gt;

&lt;p&gt;In practice, that means you get clear, structured answers to questions like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Why did this specific operation fail for this specific user?&lt;/li&gt;
&lt;li&gt;What apps are being used the most, by start count, by session time, or by role?&lt;/li&gt;
&lt;li&gt;When during the day do most errors happen and who’s hitting them?&lt;/li&gt;
&lt;li&gt;What’s the latency of backend requests in real workflows?&lt;/li&gt;
&lt;li&gt;Are end-user machines hitting CPU or memory limits?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This kind of telemetry isn’t just about performance monitoring. It’s the foundation for debugging production issues, making smart product decisions, and understanding platform-wide usage patterns.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does io.Insights work?
&lt;/h2&gt;

&lt;p&gt;io.Insights is based on the OpenTelemetry (OTEL) standard. That means everything it captures, like traces, metrics, or logs is structured, vendor-neutral, and works out of the box with tools like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Grafana&lt;/li&gt;
&lt;li&gt;Prometheus&lt;/li&gt;
&lt;li&gt;Jaeger&lt;/li&gt;
&lt;li&gt;Splunk&lt;/li&gt;
&lt;li&gt;Power BI&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Because it’s OTEL-compliant, you’re not locked into any specific vendor, and you can ingest the data however and wherever you want, locally, in the cloud, or straight into your existing dashboards.&lt;/p&gt;

&lt;p&gt;Once io.Connect is installed with Insights enabled and the OTEL Collector is configured to handle the data pipeline telemetry will roll. No major code changes are needed to start capturing info.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What does it track?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;io.Insights publishes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Platform and API metrics&lt;/strong&gt;: startup counts, usage, memory/CPU profiles, session durations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traces&lt;/strong&gt; from user actions and platform operations (like context updates or adapter calls)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Logs&lt;/strong&gt; from the io.Connect platform and from your own applications if you opt in&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why OpenTelemetry?
&lt;/h2&gt;

&lt;p&gt;OpenTelemetry has been adopted by observability vendors and enterprises as the de facto standard for instrumenting cloud-native applications, upon which the entire observability ecosystem builds. According to recent surveys, 48.5% of organizations are already using OpenTelemetry, with another 25.3% planning implementation soon. The framework has become the second-largest Cloud Native Computing Foundation (CNCF) project by number of contributors, sitting just behind Kubernetes.&lt;/p&gt;

&lt;p&gt;One of OpenTelemetry’s most compelling advantages is its vendor-neutral approach that breaks free from proprietary vendor agents. By using OpenTelemetry SDKs, organizations can change observability vendors as simply as changing configuration for exporters&lt;/p&gt;

&lt;h2&gt;
  
  
  Key OTEL Terms to understand
&lt;/h2&gt;

&lt;p&gt;OpenTelemetry offers several types of data&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Trace&lt;/strong&gt;: A full end-to-end sequence of operations, e.g. user selects a client, which triggers a context update, which triggers a backend fetch.

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Span&lt;/strong&gt;: A single step or operation inside a trace. Spans are hierarchical and connected, showing timing, duration, and relationships. Think of them as nodes in a tree.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Metric&lt;/strong&gt;: A numerical data point over time. For example, CPU usage, request counts, or session duration.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Log&lt;/strong&gt;: An event-level message, often tied to a span. Includes error details, stack traces, or any structured message your app emits.&lt;/li&gt;

&lt;/ul&gt;

&lt;h2&gt;
  
  
  What can you do with this data?
&lt;/h2&gt;

&lt;p&gt;Here are a few questions you can answer using io.Insights:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Usage &amp;amp; Behavior&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What applications are used most? By start count or by how long they’re in focus?&lt;/li&gt;
&lt;li&gt;How frequently do users switch between apps or workspaces?&lt;/li&gt;
&lt;li&gt;What’s the average session length by app or user?&lt;/li&gt;
&lt;li&gt;What departments or roles rely most on which tools?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Troubleshooting&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Which actions are error-prone and for who?&lt;/li&gt;
&lt;li&gt;Are performance issues tied to specific machines or network latency?&lt;/li&gt;
&lt;li&gt;Is a failing adapter being called more often than expected?&lt;/li&gt;
&lt;li&gt;When something breaks, what happened before and after?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;System Health&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How much CPU/memory is being used by Connect apps on user machines?&lt;/li&gt;
&lt;li&gt;Are certain machines regularly hitting system limits?&lt;/li&gt;
&lt;li&gt;Are backend services responding consistently across users?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this is driven by the instruments that come built-in and it can be extended with your own events, metrics, or log data using simple APIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do you need to run it?
&lt;/h2&gt;

&lt;p&gt;Here’s what the setup typically looks like:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Install&lt;/strong&gt; io.Connect with Insights enabled.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Set up&lt;/strong&gt; a local or remote OTEL collector (e.g. with Docker).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configure&lt;/strong&gt; io.Connect to send telemetry to the collector.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connect&lt;/strong&gt; your collector to your analytics or dashboard backend.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That’s it, you’re now streaming metrics, logs, and traces out of your platform, ready for analysis. Of course, the config could be fetched from io.Manager, using its remote configuration feature&lt;/p&gt;

&lt;h2&gt;
  
  
  Sample Setup
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Visualizing metrics with Grafana&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Grafana is a powerful platform that can be used to visualize metrics, traces and logs all in one place. This makes it convenient to jump for example, from a spike in a particular metric to the relevant traces with the same labels/time window. The dashboards, graph metrics and overlay annotations help track cause → effect and link to logs or trace details. It also offers additional features like alerting, multi-channel notifications, and a library of community dashboards and plugins.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to set up Grafana?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Grafana is offered as Grafana Cloud and an open-source download. If you want to keep your data local go with the downloads, it’s super straightforward. Simply visit &lt;a href="https://grafana.com/grafana/download" rel="noopener noreferrer"&gt;https://grafana.com/grafana/download&lt;/a&gt; , if you are a Windows user, select Windows and download the Standalone Windows Binaries zip → right-click and select the &lt;code&gt;unblock&lt;/code&gt; checkbox, and click OK, now unzip the archive to your preferred location. In that folder, open /bin and run &lt;code&gt;grafana-server.exe&lt;/code&gt;, which will start Grafana. Now you can open a browser and enter &lt;a href="http://localhost:3000/" rel="noopener noreferrer"&gt;http://localhost:3000/&lt;/a&gt; (or replace the port if preferred).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevvzi2tzm860sw4wwjyf.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fevvzi2tzm860sw4wwjyf.jpeg" alt="image|690x345" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Default login credentials are admin/admin (make sure to change your password and keep it safe). That’s it you can now play around.&lt;/p&gt;

&lt;p&gt;In the left-hand sidebar select &lt;code&gt;Connections&lt;/code&gt; → &lt;code&gt;Data Sources&lt;/code&gt;, click &lt;strong&gt;+ Add new data source&lt;/strong&gt; and select Prometheus.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why do I need Prometheus?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Grafana is your cockpit used to visualize the &lt;em&gt;dashboard&lt;/em&gt;, but the downloadable version doesn’t keep metrics on disk. You still need a database that will &lt;em&gt;store&lt;/em&gt; every sample, answer queries, and expose an HTTP API. Prometheus fills that role.&lt;/p&gt;

&lt;p&gt;Grafana ships “native support for Prometheus”, so you can point it at a running Prometheus and it can query with PromQL.&lt;/p&gt;

&lt;p&gt;Prometheus can be downloaded from &lt;a href="https://prometheus.io/download/" rel="noopener noreferrer"&gt;https://prometheus.io/download/&lt;/a&gt; and configured via &lt;code&gt;prometheus.yml&lt;/code&gt; following the steps here &lt;a href="https://prometheus.io/docs/introduction/first_steps/" rel="noopener noreferrer"&gt;https://prometheus.io/docs/introduction/first_steps/&lt;/a&gt; . By default Prometheus runs on &lt;code&gt;localhost:9090&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Prometheus config (scrape the Collector)&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Add a scrape job to your prometheus.yml:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;scrape_configs:
  - job_name: 'otel-collector'
    static_configs:
      - targets: ['localhost:9464']   # default Prometheus exporter endpoint
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Prometheus will now scrape all metrics the collector exposes (including metrics your apps send via OTLP that the collector converts to Prometheus format).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I skip Prometheus?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There are several alternatives that play well with Grafana&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Grafana&lt;/strong&gt; &lt;strong&gt;Agent / Alloy&lt;/strong&gt; - embeds a cut‑down Prometheus engine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Grafana Cloud or Mimir&lt;/strong&gt; – easiest to set up, but runs remotely&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Other TSDBs&lt;/strong&gt; ― InfluxDB, VictoriaMetrics, TimescaleDB, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi98xrgow0cqhzb1xyrt9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi98xrgow0cqhzb1xyrt9.png" alt="image|690x256" width="800" height="297"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Visualize traces in Grafana to combine the power of metrics and traces&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;To visualize traces in Grafana, you’ll need a tracing backend since Prometheus is designed specifically for metrics. One of the easiest ways is to use Jaeger or Grafana’s own Tempo.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why Jaeger or Tempo?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Grafana natively supports both Jaeger and Tempo data sources. They’re optimized specifically for handling distributed traces, allowing you to quickly navigate from high-level metrics down into detailed operation-level data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setting Up Jaeger&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Jaeger is an open-source tracing system, straightforward to install locally:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Download the latest Jaeger Windows binary from &lt;a href="https://github.com/jaegertracing/jaeger/releases" rel="noopener noreferrer"&gt;Jaeger releases&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Unzip the package into a folder like C:\Jaeger.&lt;/li&gt;
&lt;li&gt;Open PowerShell and run:
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd C:\Jaeger
.\jaeger-all-in-one.exe --collector.otlp.enabled=true --collector.otlp.http.host-port=:4318
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This command starts Jaeger with OTLP support. It will listen for traces sent to &lt;a href="http://localhost:4318/v1/traces" rel="noopener noreferrer"&gt;http://localhost:4318/v1/traces&lt;/a&gt;, and expose a web UI at &lt;a href="http://localhost:16686" rel="noopener noreferrer"&gt;http://localhost:16686&lt;/a&gt;. Typical ports are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Thrift HTTP ingest: &lt;a href="http://localhost:14268/api/traces" rel="noopener noreferrer"&gt;http://localhost:14268/api/traces&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;gRPC ingest: localhost:14250&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Connecting Jaeger to Grafana&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Follow the setup guide from Grafana here - &lt;a href="https://grafana.com/docs/grafana/latest/datasources/jaeger/" rel="noopener noreferrer"&gt;https://grafana.com/docs/grafana/latest/datasources/jaeger/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenTelemetry Collector config&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here’s a sample for pointing an OTEL collector to Prometheus and Jaeger running locally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Apps send OTLP → Collector (:4317 gRPC / :4318 HTTP).&lt;/li&gt;
&lt;li&gt;Collector &lt;strong&gt;serves&lt;/strong&gt; metrics at :8889/metrics.&lt;/li&gt;
&lt;li&gt;Collector sends traces to &lt;strong&gt;Jaeger&lt;/strong&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;receivers:
  otlp:
    protocols:
      grpc:        # default port 4317
      http:        # default port 4318

processors:
  batch: {}

exporters:
  # Prometheus: expose /metrics that Prometheus will scrape
  prometheus:
    endpoint: "0.0.0.0:8889"   # collector will serve metrics here
    namespace: "otelcol"

  # --- Choose ONE of the Jaeger options below ---

  # Option A (most universal): Jaeger Thrift over HTTP (Jaeger all-in-one/collector default)
  jaeger:
    endpoint: "http://localhost:14268/api/traces"
    tls:
      insecure: true

  # Option B (if your Jaeger exposes native OTLP 4317/4318 — newer Jaeger versions)
  # otlp/jaeger:
  #   endpoint: "http://localhost:4318"   # or "localhost:4317" for gRPC
  #   # For HTTP:
  #   tls:
  #     insecure: true
  #   # For HTTP, set explicit protocol:
  #   # If your collector version needs it:
  #   # headers: {}
  #   # compression: none

service:
  pipelines:
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheus]
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [jaeger]        # or [otlp/jaeger] if you chose Option B

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Read next
&lt;/h2&gt;

&lt;p&gt;In the &lt;a href="https://community.interop.io/t/track-down-issues-fast-with-io-insights/" rel="noopener noreferrer"&gt;next article&lt;/a&gt;, we walk through a problem one of our users reported and show how you can track the issue all the way down to the backend service much faster than before.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Useful links&lt;/strong&gt;
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;a href="https://docs.interop.io/insights" rel="noopener noreferrer"&gt;io.Insights Documentation&lt;/a&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.interop.io/t/track-down-issues-fast-with-io-insights/9" rel="noopener noreferrer"&gt;https://community.interop.io/t/track-down-issues-fast-with-io-insights/9&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://community.interop.io/t/answering-questions-with-io-insights-metrics-and-grafana/153" rel="noopener noreferrer"&gt;https://community.interop.io/t/answering-questions-with-io-insights-metrics-and-grafana/153&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>monitoring</category>
      <category>tooling</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
