The ultimate objective is to detect if a visualforce page (or the lightning component embedded within it) is already being viewed/used by a user when someone else opens it and subsequently restrict edit'ability as needed.

I started off looking into Salesforce Platform Events, but am open to better approaches.

Referencing Platform Event Notifications in a Lightning Component and lightning:empApi documentation here, I was able to publish/subscribe to platform events in Lightning Experience without issues.

However, when I dropped the same component onto a Visualforce page (Lightning Out), empApi.subscribe() in ControllerJS (please see below) doesn't get called at all, resulting in subscription service to not work...? I don't see exceptions anywhere either. Is this a bug or could I be missing something?

I was hoping to utilize the stateful nature of lightning component UI and pair it with init and change events in component to capture and restrict access based on who is viewing the page.

Because I couldn't get above to work, another way would be to subscribe to platform event notifications with Apex Triggers, BUT wouldn't that require me to create a separate object to track who opened the page first and surround my logic around that object? Now I am asking myself, why even use platform events if that is the case (and make do with just a custom object to log who is viewing the page)? So, more importantly, are platform events the right solution in this situation?

Publisher Class

public with sharing class PlatformEvents {

    public static String publish(String targetId, String entityName, String entityType){

        String returnMessage = null;

                List<Platform_Event_Test__e> events = new List<Platform_Event_Test__e>();
                events.add(new Platform_Event_Test__e(Target_Id__c = targetId, Entity_Name__c = entityName, Entity_Type__c = entityType));

                system.debug(logginglevel.ERROR, '-------------------------------> PlatformEvents publish() 1: ' + targetId + ' ' + entityName + ' ' + entityType);
                List<Database.SaveResult> publishResult = EventBus.publish(events);

                for(Database.SaveResult result : publishResult) {
                        returnMessage = 'SUCCESS';
                    else {
                        returnMessage = 'ERROR(S): ';
                        for(Database.Error error : result.getErrors())
                            returnMessage += (error.getStatusCode() + ' - ' + error.getMessage());
            } catch (Exception ex) {
                returnMessage = 'ERROR(S): ' + ex.getMessage() + ' - ' + ex.getStackTraceString();
                system.debug(logginglevel.ERROR, '-------------------------------> PlatformEvents publish(): ' + returnMessage);

        return returnMessage;


Invoking Publisher like so (via Execute Anonymous in Developer Console):

String returnMessage = PlatformEvents.publish('0081A000117cQiI', 'TEST', 'TEST');
system.debug(logginglevel.ERROR, '------------> ' + returnMessage);

Subscriber component (PlatformEventSubscriber.cmp)

<aura:component implements="flexipage:availableForAllPageTypes" access="global" >

    <aura:handler name="init" value="{!this}" action="{!c.init}" />
    <aura:attribute name="targetId" type="String" />
    <lightning:empApi aura:id="empApi" />   

    targetId = {!v.targetId} <!-- This value prints in Lightning Experience, but not in a Visualforce page via Lightning Out -->


Subscriber component ControllerJS:

        init : function(component, event, helper) {
                var empApi = component.find("empApi");

                console.log("-------------> In c:PlatformEventSubscriber.cmp controller init ");

                var errorHandler = function (message) {
                    console.log("-------------> Received error ", message);

                var channel = '/event/Platform_Event_Test__e';
                var replayId = -1;
                var callback = function (message) {
                    component.set("v.targetId", message.data.payload.Target_Id__c);

                empApi.subscribe(channel, replayId, callback).then(function(value) {
                    //This line executes in Lightning Experience, but not in a Visualforce page via Lightning Out
                    console.log("-------------> Subscribed to channel " + channel);
            } catch(err){
                console.log('-------------> init ERROR: ' + err + ' ** MESSAGE: ' + err.message + ' ** STACK: ' + err.stack);

For your convenience, lightning dependency app to host Lightning Components in Visualforce page (LightningComponentApp.app):

<aura:application access="GLOBAL"  extends="ltng:outApp">
    <aura:dependency resource="c:PlatformEventSubscriber" />

For your convenience, visualforce page (LightningComponentContainer.vfp):

<apex:page title="Platform Events Test" sidebar="false">
    <apex:includeScript value="/lightning/lightning.out.js"/>  

    <div id="contentDiv"/>

        $Lightning.use("c:LightningComponentApp", function() {
                function(cmp) {
  • Is it classic SF or lightning experience? – Pranay Jaiswal Oct 30 '18 at 17:40
  • Like I mentioned in OP, I was able to publish/subscribe to platform events in Lightning Experience without issues. However, when I dropped the same component onto a Visualforce page (Lightning Out), my subscriber component is not printing targetId at all. – Lightning Evangelist Oct 30 '18 at 17:42
  • I meant was that VF page viewed insided lightning experince or classics? – Pranay Jaiswal Oct 30 '18 at 17:51
  • I 'previewed' the VF page while in Lightning Experience AND also after switching to Classic. Same thing, no value is returned. – Lightning Evangelist Oct 30 '18 at 18:03
  • @LightningEvangelist What alternative did you use to make it work your component in both classic and lightning ? – Hunt Jul 23 '20 at 5:28

lightning:empApi is not supposed to work using VF page/Lightning out.

If you see the Experience section in the documentation of this component, you will find as below. Only those components which has Lightning Out / Visualforce listed in the Experience section will work in that experience.


Lightning Experience, Salesforce Mobile App

enter image description here

  • I overlooked that part... thanks for pointing it out! – Lightning Evangelist Oct 30 '18 at 18:57
  • @Kal You're welcome! That section on the documentation is actually very good when making a decision as where the component will work vs. not. – Jayant Das Oct 30 '18 at 18:59
  • @JayantDas what could be the alternative to keep the component working in both classic and lwc with Event Notification – Hunt Jul 23 '20 at 5:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.