fullstorydev / fullstory-browser-sdk

Official FullStory SDK for JavaScript, for web browsers
MIT License
55 stars 17 forks source link

Error: FullStory is not loaded, please ensure the init function is invoked before calling FullStory API #79

Closed sohinim98 closed 3 years ago

sohinim98 commented 3 years ago

Sentry keeps throwing the FullStory is not loaded, please ensure the init function is invoked before calling FullStory API error. This is an Angular2 app and I'm initializing FullStory from app.component.ts like this -

// fullStory analytics tracking
        FullStory.init({ orgId: environment.fullstoryOrgId,
          devMode: !environment.production });
        FullStory.identify(this.user._id, {
          displayName: this.user.name,
          email: this.user.email,
          institution: this.user.org_name,
        });

We have integrated Sentry with Fullstory using @sentry/fullstory and we initialize sentry in a separate entry-error-handler.ts file and capture using Sentry.captureException(error.originalError || error);.

I tried checking if FullStory.getCurrentSessionURL(); was ready before my FullStory.identify call and it wasn't meaning that FullStory wasn't fully bootstrapped. I also read that calls to FS.event can be made prior to bootstrapping and the only time we really need FullStory to be fully bootstrapped is for session replay url (or session replay id) which we're not using.

Since there isn't an FullStory.OnReady() function for FullStory, what's the suggested solution?

van-fs commented 3 years ago

Hi @sohinim98 , thanks for opening your issue. There is the concept of _fs_ready, but I don't think that's the nature of this particular issue. You're right, the call to FullStory.init() is synchronous, and any subsequent calls like your FullStory.identify usage is valid. The APIs will be stubbed out until the recording code is fetched and bootstrapped. I'm curious about your statement:

we initialize sentry in a separate entry-error-handler.ts file

Are you referring to the ErrorHandler hook in Angular? If so, this hook is executed when app.module is evaluated and before app.component.ts's constructor. I'm wondering if the code in the ErrorHandler is registering Sentry and is indeed calling FullStory before it's inited. Can you provide a bit more detail about the ErrorHandler and when FullStory.init is called within app.component.ts? This feels like a timing issue between FullStory and Sentry SDKs.

sohinim98 commented 3 years ago

Yes, that's exactly right. SentryErrorHandler is hooked as an ErrorHandler and executed when when app.module.ts is evaluated which is before app.component.ts's constructor. Thanks for identifying the issue.

I'm calling FullStory.init in app.component.ts's constructor. I execute this.subscribers.push and call the userService to get the current user's details from the BE, and then init FullStory, so it's along the lines of this -

constructor(//...services) {
   this.subscribers.push(this.userService.user.subscribe(res => {
   this.user = res && res.user;
   if (this.user.blah) {
      // some more code
   }
   if (this.user && this.user._id) {
   // fullStory analytics tracking
        FullStory.init({ orgId: environment.fullstoryOrgId,
          devMode: !environment.production });
        FullStory.identify(this.user._id, {
          displayName: this.user.name,
          email: this.user.email,
          institution: this.user.org_name,
        });
      }
}));
}

What should I do differently?

van-fs commented 3 years ago

I have an inquiry into Sentry to see if there's a way to "lazy load" the FullStory integration. In the meantime, I think you could simply add the FullStory.init outside the AppComponent class. What I expect to happen is that as long as the FullStory.init is evaluated before the ErrorHandler, then the error should not occur. You could move this:

FullStory.init({ orgId: environment.fullstoryOrgId,
          devMode: !environment.production });

into main.ts for example.

FullStory.identify can remain in your AppComponent's constructor as you have it today. It might feel a little non-standard, but I don't think there's any functional issue. Often we suggest to load FullStory as early as possible in the <head> tag. With this change, you're just moving the evaluation earlier. Let us know if that provides some help.

patrick-fs commented 3 years ago

@sohinim98 did moving the FullStory init invocation into main.ts solve your problem?

sohinim98 commented 3 years ago

Yes, it did. @patrick-fs

patrick-fs commented 3 years ago

Great! I'm going to close this issue. Thanks for reaching out to us.