Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using SDK with Next.js and making Amplitude global #24

Open
bobthebuilder1900 opened this issue Sep 2, 2020 · 10 comments
Open

Using SDK with Next.js and making Amplitude global #24

bobthebuilder1900 opened this issue Sep 2, 2020 · 10 comments
Labels
question Further information is requested

Comments

@bobthebuilder1900
Copy link

bobthebuilder1900 commented Sep 2, 2020

Summary

Hi, I am looking into implementing this SDK on my Next.js project as it is server side rendered.

The documentation isn't clear, so I am unsure on how to actually get started, on my app.tsx I want to init amplitude and have it available on all pages and components.

import '../styles.css';
import React from 'react';
import { ProvideAuth } from 'utils/auth';
import * as Amplitude from '@amplitude/node';

import Layout from 'components/Layout';

type Props = {
  Component: React.ElementType;
  pageProps: React.Props<unknown>;
};

let client = Amplitude.init(process.env.AMPLITUDE_API_KEY)

export default function MyApp({ Component, pageProps }: Props) {
  // The context is provided to the user so the userCtx is accessible anywhere with useContext hook.
  return (
    <ProvideAuth>
      <Layout title="OWNRS" description="">
        <Component {...pageProps} />
      </Layout>
    </ProvideAuth>
  );
}

With the above, it is not initialised, as I do not use client for anything, can I simply do Amplitude.init(process.env.AMPLITUDE_API_KEY) if not, how can I make this global?

With the client side SDK, I could init on the index.js and use amplitude.getInstance() to log an event

My question is, do I need to create a utils file that does the following

import * as Amplitude from '@amplitude/node';
const amplitude = Amplitude.init(process.env.AMPLITUDE_API_KEY);
export default amplitude;

and import it on every page, then log events?

import amplitude from 'utils/amplitude'

amplitude.logEvent({
  event_type: 'Node.js Event',
  user_id: '[email protected]',
  location_lat: 37.77,
  location_lng: -122.39,
  ip: '127.0.0.1',
  event_properties: {
    keyString: 'valueString',
    keyInt: 11,
    keyBool: true
  }
});

How can I make this globally available within my app so that way data can be logged?

@bobthebuilder1900 bobthebuilder1900 added the question Further information is requested label Sep 2, 2020
@kelvin-lu
Copy link
Contributor

kelvin-lu commented Sep 2, 2020

Hi @bobthebuilder1900 ! I think the pattern you have with having is exported seems solid. I was wondering what issues you were encountering with the JS SDK for server side-rendered react?

If the JS SDK also works, you could also consider using our react sdk which wraps the JS SDK and provides useful helper components. You could also consider copying its pattern for the Node SDK and inserting the initialized node client into a top component of the React tree into the context and using context providers as necessary to fetch it within your components.

@bobthebuilder1900
Copy link
Author

The JS SDK does not work with server side rendered applications, as it relies heavily on accessing window.

Looking at the events that the node sdk sends, I am not sure I can use it as it sends the platform as Node.js and I won't be able to get devices or "Real" platforms such as Windows, Mac and Linux or browser usage.

The react amplitude sdk first paragraph says "react-amplitude is not an officially supported Amplitude SDK or library."

@kelvin-lu
Copy link
Contributor

@bobthebuilder1900 Apologies for the delayed response.

The react amplitude sdk first paragraph says "react-amplitude is not an officially supported Amplitude SDK or library."

We don't support it officially, but I think the pattern it has (and the community built amplitude-react-hooks, or just using one of those libraries) of injecting Amplitude into React's context might worthwhile to try for building a react application with Amplitude.

The JS SDK does not work with server side rendered applications, as it relies heavily on accessing window.

Unfortunately this is true, and something we're looking into. It would however align better to your use case as it provides a better API for the web. Things you could consider as workarounds while we work to solve this:

  • deferring the loading of the amplitude JS SDK to componentDidMount
  • adding a fallback window/document object

@hudsonhyunlim
Copy link

Has this been solved yet? I'm running into the same problem using amplitude JS SDK on a NextJS project.

@desmondmc
Copy link

@hudsonhyunlim As a workaround I conditionally import and init amplitude only on the browser side like this:

 let amplitude: any;
 export const initAmplitude = () => {
   if (process.browser) {
     amplitude = require('amplitude-js');
     amplitude.getInstance().init('your-amplitude-code');
   }
 };

Then in my _app.tsx

useEffect(() => {
    initAmplitude();
}, []);

Then also wrap all other amplitude functions like the init:

export const setAmplitudeUserId = (userId: string) => {
  if (process.browser) {
    amplitude.getInstance().setUserId(userId);
  }
};

const amplitudeEvent = (name: string, params?: {}) => {
  if (process.browser) {
    amplitude.getInstance().logEvent(name, params);
  }
};

@Vadorequest
Copy link

I personally use react-amplitude for Next.js pages, and @amplitude/node for APIs.

@MohamedJakkariya
Copy link

useEffect(() => {
initAmplitude();
}, []);

It works on next js. But somehow I get the following error

ReferenceError: window is not defined
    at C:\Users\MD\Desktop\webV2\node_modules\amplitude-js\amplitude.umd.js:1197:12
    at C:\Users\MD\Desktop\webV2\node_modules\amplitude-js\amplitude.umd.js:2:83
    at Object.<anonymous> (C:\Users\MD\Desktop\webV2\node_modules\amplitude-js\amplitude.umd.js:5:2)
    at Module._compile (internal/modules/cjs/loader.js:1085:14)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
    at Module.load (internal/modules/cjs/loader.js:950:32)    
    at Function.Module._load (internal/modules/cjs/loader.js:790:14)
    at Module.require (internal/modules/cjs/loader.js:974:19) 
    at require (internal/modules/cjs/helpers.js:92:18)        
    at Object.amplitude-js (C:\Users\MD\Desktop\webV2\.next\server\pages\index.js:9193:18)

After reload automatically it works. Such a weird thing. Is anyone the same as me?

@desmondmc
Copy link

desmondmc commented Aug 19, 2021

@MohamedJakkariya window is not defined usually means the code is trying to access the browser window on the server. You should wrap your code like...

if (process.browser) {
    useEffect(() => {
      initAmplitude();
    }, []);
}

@MohamedJakkariya
Copy link

@desmondmc Thanks for your reply. By the way, I found my issue. I just try to access the amplitude before loading it into the window. I realized. So I fixed it.

@hannut91
Copy link

hannut91 commented Sep 10, 2021

Don't calls hooks inside conditions.

I think it should be like this.

useEffect(() => {
  if (router.isReady) {
    initAmplitude();
  }
}, [router.isReady]);

See also

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

7 participants