I have an LWC which subscribes and display a custom Platform Event

import { LightningElement } from 'lwc';
import { subscribe, unsubscribe, onError } from 'lightning/empApi';

export default class NotificationsLog extends LightningElement {
    subscription = {};
    events = [];

    connectedCallback() {
        onError(error => {
            console.log('Received error from server: ', JSON.stringify(error));

        subscribe('/event/NotificationReceived__e', -1, this.handleEvent).then(response => {
            this.subscription = response;

embedded (via Lightning-Out) into a Visualforce page

    <apex:includeLightning />

    <div id="notificationsLog" />

        $Lightning.use("c:myApp", () => {
            $Lightning.createComponent("c:notificationsLog", {}, "notificationsLog");

I also registered the LWC in the Aura app

<aura:application extends="ltng:outApp">
    <aura:dependency resource="markup://c:notificationsLog"/>

Nothing happens when I fire such an Event

EventBus.publish( new NotificationReceived__e(...));

and the root cause seems to be the subscribe is never successful

enter image description here

3 Answers 3


Not clear how to interpret "Targets" in the documentation (and where Lightning-Out would fit) but e.g. lighting-card works for these Targets:

  • Lightning Experience
  • Experience Builder Sites
  • Salesforce Mobile App
  • Standalone Lightning App

but lightning-emp-api only for this Target:

  • Lightning Experience

I had to roll my own CometD (pretty annoying) to have Platform Events working for "Experience Builder Sites". The same may be true for your Lightning-Out case.

  • Would you be able to provide sample code of how to make it work with CometD and Lightning-Out? Apr 1, 2021 at 11:27
  • 2
    Hi @RobertSösemann, As part of my employer's codebase I can't post it, but the starting point was Mohith's post here salesforce.stackexchange.com/questions/289584/… with additions to handle more of the CometD lifecycle. Took a few hours so I suggest you wait to see if anyone answers explicitly about Lightning-Out.
    – Keith C
    Apr 1, 2021 at 11:53

The lightning/empApi module is applicable only inside the Lightning Container (You have to be in the Lightning Experience Builder). This is documented in the Targets section in the docs.

One reason to avoid using lightning/empAPI or even a CometD client is that there is a 50K limit on the number of event subscriptions you can have in an org with Cometd unless you purchase add-ons. Note this is a shared limit and hence if you have n users using your streaming component effectively your users can subscribe to only 50000/n. Since it is shared if you have other streaming clients in the org it's lower than that.

If you still think you want to go with the custom implementation using cometd on the platform, check this answer.

What are your options? One of the below should work

  1. Maybe go back to traditional polling that executes the query setInterval function of JavaScript.

  2. Create a Streaming client on Say Heroku with Node.js that then opens a WebSocket connection that Salesforce or any other system can listen to. Note that Salesforce itself cannot open a WebSocket due to security implications, however, Salesforce can be a client to listen to a WebSocket if CSP is configured for it. This improves efficiency from n to 1.


Let me answer my own question. All the others are right with empApi doesn't work in a Lightning-Out context with a Visualforce page. But here is how I actually solved it using an already existing CometD LWC component:

LWC Markup:

    <!-- taken from https://github.com/TheVishnuKumar/lwc-streaming-api -->

    Notifications ({events.length}):
        <template for:each={events} for:item="event">
            <li key={event.Id}>{event.txt_Body__c})</li>

LWC JS: import { LightningElement, track } from "lwc";

export default class NotificationsLog extends LightningElement {

    events = [];

        this.events.push( event.detail.payload.data.payload );
        this.events = JSON.parse(JSON.stringify(this.events));

        console.log( JSON.stringify(event.detail.error) );



    cometD() {
        return this.template.querySelector('.cometD');

I am still facing some issues but I am sure I will solve them.

  1. Can't find out how to replay events (an option in empApi exists for that)
  2. The first event fired from the VF page is not displayed

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .