DEV Community

Cover image for [workaround] Reference the cookie value in _document.js in Next.js
Yuki Shindo
Yuki Shindo

Posted on

[workaround] Reference the cookie value in _document.js in Next.js

I wrote this post a few days ago in Japanese as well.
The post in Japanese is here.

Overview and Notes

This article describes how to reference the cookie value in _document.js of Next.js.
Since the code is basically written in TypeScript, the file name may be written as _document.tsx instead of _document.js from now on, but it is assumed to be the same file in both cases.

There may not be many cases where you want to refer to the cookie value in _document.js, But for example, there are cases where you want to control loading scripts in <head> tags by looking at the cookie value.
(For example, you may want to enable or disable Google Analytics.)

First of all, there are a few things to keep in mind.

First, the way we write here is workaround.
That's because I don't think it's a feature provided on the Next.js side.
(Because looking at the behavior of Next.js, it's hard to discern if this is a pre-expected method.)

So if you can avoid using this method, it's better.
I'm looking into it myself to see if there is a more straightforward method.

Next, I need to run the getServerSideProps process, which is provided in Next.js as a way to achieve what we want to achieve this time.
So if you're hosting your site as a static site on Nelify, for example, you can't use getServerSideProps, so you can't use this approach.
(I haven't checked if there is an alternative.)

Note (About version of Next.js)

As I mentioned earlier, I'm not sure if this is what Next.js is supposed to do or not, so I'll add the possibility that the behavior may change depending on the Next.js version.

This code is verified with version "9.5.5".

Reference the cookie value in _document.js in Next.js

First, I wrote the code for verification.
If you want to see the actual behavior, clone this code locally and run it.

Next.js sample of get cookie value at document.tsx

The above code shows how to refer to the cookie value in _document.js.

  • Set up the getServerSideProps function in the page you want to call (such as pages/index.tsx).
    • You don't need to write a process. -> getServerSideProps is written only because we want to run it once when drawing the page.
  • Referencing the cookie value from ctx.req.headers.cookie in _document.js

Here's the code that actually references the cookie value in _document.tsx.
Here's a snippet of code from the repository above.

export default class MyDocument extends Document<Props> {
  static async getInitialProps(ctx) {
    const initialProps = await Document.getInitialProps(ctx);

    let hasCookie: boolean = false;

    if (ctx.req && ctx.req.headers.cookie) {
      console.log('cookie values: ', ctx.req.headers.cookie);
      hasCookie = true;
    }

    return { ...initialProps, hasCookie };
  }

  render() {
    console.log('hasCookie: ', this.props.hasCookie);
Enter fullscreen mode Exit fullscreen mode

I didn't seem to have getServerSideProps implemented in _document.tsx, so I used getInitialProps to get the value of the cookie once.

However, even if this code actually contains the value of the cookie, it doesn't necessarily contain the value in ctx.req.headers.cookie.
The getServerSideProps call works in pages/index.tsx, but if you comment out this code, you won't be able to see the cookie in the above _document.tsx.

diff --git a/pages/index.tsx b/pages/index.tsx
index 99ea97d..23a6337 100644
--- a/pages/index.tsx
+++ b/pages/index.tsx
@@ -12,9 +12,11 @@ const IndexPage: React.FC = (): JSX.Element => (
   </div>
 );

+/*
 export async function getServerSideProps() {
   console.log('----------> Call getServerSideProps');
   return { props: {} };
 }
+*/
Enter fullscreen mode Exit fullscreen mode

Specifically, the ctx.req will be undefined.
Apparently, only after getServerSideProps works, the value is stored in ctx.req in _document.tsx.

I think this code in Next.js may be helpful for this kind of behavior.
(Sorry if I got it wrong!)

https://github.com/vercel/next.js/blob/5cab03fef0782b4ecd7dbe4ec5bd10d10554650f/packages/next/next-server/server/render.tsx#L717-L728

After getServerSideProps runs, the values are put into ctx.req.
So now we need to refer to those values (in this case, ctx.req) on the document side after running it once on the server side.

If anyone knows of a better way to do this, please comment.

Thanks for reading!

Top comments (2)

Collapse
 
alejandrocabriales profile image
Manuel Alejandro

I am getting this error
Property 'hasCookie' does not exist on type 'Readonly>[] | ReactFragment | undefined; } & HtmlProps>'.

Collapse
 
shinshin86 profile image
Yuki Shindo

Thanks for your comment. Sorry it took me so long to reply.

Since my post, the version of Next.js has also been updated, so it is possible that it no longer works with the current version.

If you don't mind, would it be possible for you to provide us with the details of the error?
It would be easier for us to investigate if you include the version of Next.js and Node.js and etc.