I want to get the page's full URL or site hostname like the image below on Static Site Generator.
I will try with window.location.hostname
, but it doesn't work.
The error: window not defined.
I want to get the page's full URL or site hostname like the image below on Static Site Generator.
I will try with window.location.hostname
, but it doesn't work.
The error: window not defined.
If you want the hostname inside getInitialProps on server side, still you can get it from req
Home.getInitialProps = async(context) => {
const { req, query, res, asPath, pathname } = context;
if (req) {
let host = req.headers.host // will give you localhost:3000
}
}
With server-side rendering (getServerSideProps
), you can use context.req.headers.host
:
import type { GetServerSideProps, NextPage } from "next";
type Props = { host: string | null };
export const getServerSideProps: GetServerSideProps<Props> =
async context => ({ props: { host: context.req.headers.host || null } });
const Page: NextPage<Props> = ({ host }) => <p>Welcome to {host || "unknown host"}!</p>;
export default Page;
But with static generation (getStaticProps
), the hostname is not available, because there is no request to get it from. In general, a server doesn't know its own public hostname, so you need to tell it. Using Next.js environment variables, put this in .env.local
:
HOST=example.com
Then access it with process.env['HOST']
:
import type { GetStaticProps } from "next";
export const getStaticProps: GetStaticProps<Props> =
async context => ({ props: { host: process.env['HOST'] || null }});
If you want to get the full URL:
import { useRouter } from 'next/router';
const { asPath } = useRouter();
const origin =
typeof window !== 'undefined' && window.location.origin
? window.location.origin
: '';
const URL = `${origin}${asPath}`;
console.log(URL);
The place where you are accessing the window
make sure you add a check so that code is executed only on the browser and no during SSG"
if (typeof window !== 'undefined') {
const hostname = window.location.hostname;
}
Update:
If you have specified basePath
in next.config.js
:
module.exports = {
basePath: 'https://www.example.com/docs',
}
Then using useRouter
, you can access the base path:
import { useRouter } from 'next/router'
function Component() {
const router = useRouter();
console.log({ basePath: router.basePath});
// { basePath: 'https://www.example.com/docs' }
...
}
But if you have a relative base path then you can use the first approach
Consider this package > next-absolute-url
import absoluteUrl from 'next-absolute-url'
const { origin } = absoluteUrl(req)
const apiURL = `${origin}/api/job.js`
If you deployed your Next.js app with now the apiURL will be something like https://your-app.now.sh/api/job.js
.
However, if you are running the app locally the apiURL will be http://localhost:8000/api/job.js
instead.
Using typeof window !== 'undefined'
is the secure way. if (window) {}
will run you into problems.
const hostname = typeof window !== 'undefined' && window.location.hostname ? window.location.hostname : '';
const origin = typeof window !== 'undefined' && window.location.origin ? window.location.origin : '';
Using above code will give you the frontend/outside hostname/origin the client using: example.com
, www.example.com
, www.example.com:80
and so on, not the localhost
stuff. useRouter()
will return the server side hostname/origin (localhost
, localhost:3000
)
I believe you're better of doing this with a combination of useRouter
and useEffect
hooks. In my case I wanted to dynamically set the og:url
of my webpage. This is what I did. We have router.pathname
as a dependency so that ogUrl
is updated every time we move to a different page.
import { useRouter } from "next/router";
import { useState, useEffect } from "react";
const MyComponent = () => {
const router = useRouter();
const [ogUrl, setOgUrl] = useState("");
useEffect(() => {
const host = window.location.host;
const baseUrl = `https://${host}`;
setOgUrl(`${baseUrl}${router.pathname}`);
}, [router.pathname]);
return <div></div>
}
You need to ensure your access to window.location.hostname
happens on the client-side only, and not during server-side rendering (where window
does not exist). You can achieve that by moving it to a useEffect
callback in your component.
function Component() {
useEffect(() => {
console.log(window.location.hostname)
console.log(window.location.href) // Logs `http://localhost:3000/blog/incididunt-ut-lobare-et-dolore`
}, [])
// Remaining code of the component
}
Here's how I solved it, and this also works with Next.js 13 App Router:
Create a hook, call it use-origin.jsx (or .tsx), and add it to the /hooks folder in the root:
'use client'; // this is Next 13 App Router stuff
import { useEffect, useState } from "react";
export default function useOrigin() {
const [mounted, setMounted] = useState(false);
const origin = typeof window !== 'undefined' && window.location.origin ? window.location.origin : '';
useEffect(() => {
setMounted(true)
}, [])
if (!mounted) {
return null
}
return origin;
}
Now use this hook to access your dynamic BASE_URL route:
"use client";
import useOrigin from "@/hooks/use-origin"
export default function Test() {
const origin = useOrigin();
return (
<div>{origin}</div>
)
}
req.headers are Symbols and not Objects, so to get value, you use the get method
const host = req.headers.get("host"); // stackoverflow.com
Using a middleware.js file that you add to the root of your project can give you access to the host name and provide a lot of flexibility to perform actions based on it if needed.
https://nextjs.org/docs/advanced-features/middleware
// Example: redirecting a domain to a subdomain
import { NextResponse } from "next/server";
// This function can be marked `async` if using `await` inside
export function middleware(request) {
// Currently there is no main site so we redirect to the subdomain.
const host = request.headers.get("Host");
if (
process.env.NODE_ENV === "production" &&
host.startsWith("mydomain.com")
) {
return NextResponse.redirect(new URL("https://mysubdomain.mydomain.com"));
} else if (
process.env.NODE_ENV === "staging" &&
host.startsWith("staging.mydomain.com")
) {
return NextResponse.redirect(
new URL("https://mysubdomain-staging.mydomain.com")
);
}
}
AFAIK there are two ways of doing this:
Next JS provides us with the useRouter hook, first you have to import it in your component, then, to use the router object, you just have to declare it. For example:
const router = useRouter();
console.log(router.pathname);
const {pathname} = router; <---- To access the pathname directly.
Besides this, as @Xairoo said before, if you want to use the window object, you have to check if window !== 'undefined'
to avoid errors. The window not defined error happens because Next JS use NodeJS to render the app and the window object is not defined in Node JS.
You can find a more detailed explanation in this link.
none oh the answers above solved the problem and this is the solution i figured it out :
function return_url(context) {
if (process.env.NODE_ENV === "production") {
// if you are hosting a http website use http instead of https
return `https://${context.req.rawHeaders[1]}`;
} else if (process.env.NODE_ENV !== "production") {
return "http://localhost:3000";
}
}
and on the getServerSideProps or getStaticProps functions you use
export async function getServerSideProps(context) {
let url = return_url(context);
const data = await fetch(`${url}/yourEndPoint`).then((res) => res.json());
return {
props: {
data: data,
},
};
}
According to the answer mentioned here, you can use below code to get hostname in Next 13 using the new app directory (for server side components):
import { headers } from 'next/headers';
export default function Home() {
const headersList = headers();
headersList.get('host'); // to get domain
headersList.get('next-url'); // to get url
return <div>....</div>
}
NOTE: please note that Using it in a layout or page will opt a route into dynamic rendering at request time
in Next.js you can do like this, by useEffect to get window.location.origin in client side, and set it to state.
work fine in : { "next": "12.1.6", "react": "18.1.0", }
const Home: NextPage = () => {
const { asPath, query } = useRouter();
const [loading, setLoading] = useState(false);
const [loginCallBackURL, setLoginCallBackURL] = useState("");
useEffect(() => {
setLoginCallBackURL(
`${window.location.origin}/${query.redirect ? query.redirect : "user"}`,
);
}, []);
// if you do something like this, it can't get loginCallBackURL
// const loginCallBackURL = useMemo(() => {
// if (typeof window !== 'undefined') {
// return `${window.location.origin}/${
// query.redirect ? query.redirect : "user"
// }`;
// }
// return asPath;
// }, [asPath, query]);
return (
<div>
<Button
variant="contained"
href={queryString.stringifyUrl({
url: `${publicRuntimeConfig.API_HOST}/auth/google/login`,
query: {
callbackURL: loginCallBackURL,
},
})}
>
Sign in with google
</Button>
</div>
);
};
export default Home;
We can get current url like this:
import { useRouter } from 'next/router';
const router = useRouter();
const origin = typeof window !== 'undefined' && window.location.origin ? window.location.origin : '';
const address_url = origin+router.asPath;