From 3e489690a4a8d9cb77323e844bbdcbc42e443c7b Mon Sep 17 00:00:00 2001 From: umsungjun Date: Tue, 23 Jun 2026 09:09:13 +0900 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=ED=81=AC=EB=A1=A4=EB=9F=AC=20?= =?UTF-8?q?=EC=83=89=EC=9D=B8=EC=9D=84=20=EC=A0=9C=EC=96=B4=ED=95=98?= =?UTF-8?q?=EB=8A=94=20robots=20prop=20=EC=B6=94=EA=B0=80=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- src/ReactHeadSafe.tsx | 8 ++++++ src/test/ReactHeadSafe.test.tsx | 45 +++++++++++++++++++++++++++++++++ src/types.ts | 8 ++++++ 3 files changed, 61 insertions(+) diff --git a/src/ReactHeadSafe.tsx b/src/ReactHeadSafe.tsx index 36a908b..edd4f79 100644 --- a/src/ReactHeadSafe.tsx +++ b/src/ReactHeadSafe.tsx @@ -33,6 +33,7 @@ export const ReactHeadSafe: FC = ({ ogLocale, twitterSite, twitterCreator, + robots, }) => { useLayoutEffect(() => { // Track selectors for meta/link tags inserted in this effect run. @@ -125,6 +126,12 @@ export const ReactHeadSafe: FC = ({ insertedSelectors.push('meta[name="twitter:creator"]'); } + // Update robots meta tag (controls crawler indexing, e.g. "noindex,follow") + if (robots !== undefined) { + updateMetaTag('name', 'robots', robots); + insertedSelectors.push('meta[name="robots"]'); + } + // Cleanup: remove every tag this effect inserted. // - On deps change: runs before the next effect, clearing stale tags // (handles prop → undefined transitions). @@ -148,6 +155,7 @@ export const ReactHeadSafe: FC = ({ ogLocale, twitterSite, twitterCreator, + robots, ]); return null; diff --git a/src/test/ReactHeadSafe.test.tsx b/src/test/ReactHeadSafe.test.tsx index 2fa8729..1023f53 100644 --- a/src/test/ReactHeadSafe.test.tsx +++ b/src/test/ReactHeadSafe.test.tsx @@ -634,6 +634,51 @@ describe('ReactHeadSafe', () => { }); }); + describe('robots meta tag', () => { + it('should create robots meta tag', () => { + render(); + + const metaTag = document.querySelector('meta[name="robots"]'); + expect(metaTag).toBeInTheDocument(); + expect(metaTag?.getAttribute('content')).toBe('noindex,follow'); + }); + + it('should update robots meta tag when prop changes', () => { + const { rerender } = render(); + rerender(); + + const metaTag = document.querySelector('meta[name="robots"]'); + expect(metaTag?.getAttribute('content')).toBe('noindex,nofollow'); + }); + + it('should prevent duplicate robots meta tags', () => { + const { rerender } = render(); + rerender(); + + const metaTags = document.querySelectorAll('meta[name="robots"]'); + expect(metaTags).toHaveLength(1); + expect(metaTags[0].getAttribute('content')).toBe('noindex,nofollow'); + }); + + it('should remove robots meta tag on unmount', () => { + const { unmount } = render(); + unmount(); + + expect( + document.querySelector('meta[name="robots"]') + ).not.toBeInTheDocument(); + }); + + it('should remove robots meta tag when prop becomes undefined', () => { + const { rerender } = render(); + rerender(); + + expect( + document.querySelector('meta[name="robots"]') + ).not.toBeInTheDocument(); + }); + }); + describe('cleanup on unmount', () => { it('should remove all inserted meta and link tags on unmount', () => { const { unmount } = render( diff --git a/src/types.ts b/src/types.ts index ecd9d3b..898ccac 100644 --- a/src/types.ts +++ b/src/types.ts @@ -48,4 +48,12 @@ export interface ReactHeadSafeProps { twitterSite?: string; /** The Twitter @username of the content author (twitter:creator), e.g. "@author" */ twitterCreator?: string; + /** + * The robots meta tag content controlling crawler indexing, e.g. "noindex,follow", "noindex,nofollow". + * + * Note: a JS-injected `noindex` is only honored by crawlers that render JavaScript + * (e.g. Googlebot, with delay). Non-JS crawlers ignore it. For pages that must be + * reliably excluded, use a server-side `X-Robots-Tag: noindex` header instead. + */ + robots?: string; } From 346bad4bc00d33cc42a28631d35c03f77f354caf Mon Sep 17 00:00:00 2001 From: umsungjun Date: Tue, 23 Jun 2026 09:09:13 +0900 Subject: [PATCH 2/6] =?UTF-8?q?docs:=20robots=20prop=EA=B3=BC=20CSR=20?= =?UTF-8?q?=ED=99=98=EA=B2=BD=EC=9D=98=20noindex=20=ED=95=9C=EA=B3=84=20?= =?UTF-8?q?=EB=AC=B8=EC=84=9C=ED=99=94=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- README.ko.md | 33 ++++++++++++++++++--------------- README.md | 33 ++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/README.ko.md b/README.ko.md index a43224f..6cc3fa9 100644 --- a/README.ko.md +++ b/README.ko.md @@ -115,21 +115,24 @@ function MyPage() { ### ReactHeadSafeProps -| Prop | Type | Description | -| ---------------- | -------- | ------------------------------------------------------------------------ | -| `title` | `string` | `document.title`에 설정될 페이지 제목 | -| `description` | `string` | SEO를 위한 메타 설명 태그 콘텐츠 | -| `keywords` | `string` | SEO를 위한 메타 키워드 태그 콘텐츠 | -| `ogTitle` | `string` | 소셜 미디어 공유를 위한 Open Graph 제목 (og:title) | -| `ogDescription` | `string` | 소셜 미디어 공유를 위한 Open Graph 설명 (og:description) | -| `ogImage` | `string` | 소셜 미디어 공유를 위한 Open Graph 이미지 URL (og:image) | -| `ogUrl` | `string` | 소셜 미디어 공유를 위한 Open Graph URL (og:url) | -| `ogType` | `OgType` | Open Graph 타입 (og:type). 표준 12개 값 자동완성 + 임의 string 모두 허용 | -| `canonicalUrl` | `string` | SEO를 위한 페이지의 대표 URL (``) | -| `ogSiteName` | `string` | 소셜 미디어 공유를 위한 사이트 이름 (og:site_name) | -| `ogLocale` | `string` | 콘텐츠의 언어/지역 코드 (og:locale), 예: `"ko_KR"`, `"en_US"` | -| `twitterSite` | `string` | 웹사이트의 Twitter 계정 (twitter:site), 예: `"@mysite"` | -| `twitterCreator` | `string` | 콘텐츠 작성자의 Twitter 계정 (twitter:creator), 예: `"@author"` | +| Prop | Type | Description | +| ---------------- | -------- | -------------------------------------------------------------------------------------------- | +| `title` | `string` | `document.title`에 설정될 페이지 제목 | +| `description` | `string` | SEO를 위한 메타 설명 태그 콘텐츠 | +| `keywords` | `string` | SEO를 위한 메타 키워드 태그 콘텐츠 | +| `ogTitle` | `string` | 소셜 미디어 공유를 위한 Open Graph 제목 (og:title) | +| `ogDescription` | `string` | 소셜 미디어 공유를 위한 Open Graph 설명 (og:description) | +| `ogImage` | `string` | 소셜 미디어 공유를 위한 Open Graph 이미지 URL (og:image) | +| `ogUrl` | `string` | 소셜 미디어 공유를 위한 Open Graph URL (og:url) | +| `ogType` | `OgType` | Open Graph 타입 (og:type). 표준 12개 값 자동완성 + 임의 string 모두 허용 | +| `canonicalUrl` | `string` | SEO를 위한 페이지의 대표 URL (``) | +| `ogSiteName` | `string` | 소셜 미디어 공유를 위한 사이트 이름 (og:site_name) | +| `ogLocale` | `string` | 콘텐츠의 언어/지역 코드 (og:locale), 예: `"ko_KR"`, `"en_US"` | +| `twitterSite` | `string` | 웹사이트의 Twitter 계정 (twitter:site), 예: `"@mysite"` | +| `twitterCreator` | `string` | 콘텐츠 작성자의 Twitter 계정 (twitter:creator), 예: `"@author"` | +| `robots` | `string` | 크롤러 색인을 제어하는 robots 메타 태그 콘텐츠, 예: `"noindex,follow"`, `"noindex,nofollow"` | + +> **주의:** JS로 주입된 `robots="noindex"`는 JavaScript를 렌더링하는 크롤러(예: Googlebot, 단 지연 있음)만 인식합니다. JS를 실행하지 않는 크롤러(상당수의 봇, 소셜 미디어 프리뷰 봇 등)는 이 태그를 무시하므로 페이지가 여전히 색인될 수 있습니다. 반드시 확실하게 색인에서 제외해야 하는 페이지라면, 서버 측 `X-Robots-Tag: noindex` 헤더를 사용하세요. ### Twitter Card 지원 diff --git a/README.md b/README.md index 649d65c..e226d27 100644 --- a/README.md +++ b/README.md @@ -118,21 +118,24 @@ That's it! The component will automatically: ### ReactHeadSafeProps -| Prop | Type | Description | -| ---------------- | -------- | ------------------------------------------------------------------------------------------------ | -| `title` | `string` | The page title that will be set in the `document.title` | -| `description` | `string` | The meta description tag content for SEO | -| `keywords` | `string` | The meta keywords tag content for SEO | -| `ogTitle` | `string` | The Open Graph title (og:title) for social media sharing | -| `ogDescription` | `string` | The Open Graph description (og:description) for social media sharing | -| `ogImage` | `string` | The Open Graph image URL (og:image) for social media sharing | -| `ogUrl` | `string` | The canonical URL of your object that will be used as its permanent ID in the graph (og:url) | -| `ogType` | `OgType` | The type of your object (og:type). Autocompletes 12 standard OG values; also accepts any string. | -| `canonicalUrl` | `string` | The canonical URL of the page for SEO (``) | -| `ogSiteName` | `string` | The site name for social media sharing (og:site_name) | -| `ogLocale` | `string` | The locale of the content (og:locale), e.g. `"en_US"`, `"ko_KR"` | -| `twitterSite` | `string` | The Twitter @username of the website (twitter:site), e.g. `"@mysite"` | -| `twitterCreator` | `string` | The Twitter @username of the content author (twitter:creator), e.g. `"@author"` | +| Prop | Type | Description | +| ---------------- | -------- | ------------------------------------------------------------------------------------------------------- | +| `title` | `string` | The page title that will be set in the `document.title` | +| `description` | `string` | The meta description tag content for SEO | +| `keywords` | `string` | The meta keywords tag content for SEO | +| `ogTitle` | `string` | The Open Graph title (og:title) for social media sharing | +| `ogDescription` | `string` | The Open Graph description (og:description) for social media sharing | +| `ogImage` | `string` | The Open Graph image URL (og:image) for social media sharing | +| `ogUrl` | `string` | The canonical URL of your object that will be used as its permanent ID in the graph (og:url) | +| `ogType` | `OgType` | The type of your object (og:type). Autocompletes 12 standard OG values; also accepts any string. | +| `canonicalUrl` | `string` | The canonical URL of the page for SEO (``) | +| `ogSiteName` | `string` | The site name for social media sharing (og:site_name) | +| `ogLocale` | `string` | The locale of the content (og:locale), e.g. `"en_US"`, `"ko_KR"` | +| `twitterSite` | `string` | The Twitter @username of the website (twitter:site), e.g. `"@mysite"` | +| `twitterCreator` | `string` | The Twitter @username of the content author (twitter:creator), e.g. `"@author"` | +| `robots` | `string` | The robots meta tag content controlling crawler indexing, e.g. `"noindex,follow"`, `"noindex,nofollow"` | + +> **Warning:** A JS-injected `robots="noindex"` is only honored by crawlers that render JavaScript (e.g. Googlebot, with delay). Non-JS crawlers (many bots, social preview crawlers) ignore it, so the page may still be indexed. For pages that must be reliably excluded from indexing, use a server-side `X-Robots-Tag: noindex` header instead. ### Twitter Card Support From cee2f729d8c59b652323557a677831947cb9b438 Mon Sep 17 00:00:00 2001 From: umsungjun Date: Tue, 23 Jun 2026 09:09:13 +0900 Subject: [PATCH 3/6] =?UTF-8?q?chore:=20=EB=B2=84=EC=A0=84=201.10.0?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=98=AC=EB=A6=BC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4.8 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 931311e..c9d8ee2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-head-safe", - "version": "1.9.0", + "version": "1.10.0", "description": "A lightweight React head manager for CSR apps. Safely manage document title, meta tags, Open Graph, and SEO metadata without duplicates. TypeScript support included.", "author": "umsungjun", "license": "MIT", From d5a25356bb8d57105dcff857f93f473cc0f2be73 Mon Sep 17 00:00:00 2001 From: umsungjun Date: Tue, 23 Jun 2026 09:12:40 +0900 Subject: [PATCH 4/6] feat: add robots prop for controlling crawler indexing --- src/ReactHeadSafe.tsx | 8 ++++++ src/test/ReactHeadSafe.test.tsx | 45 +++++++++++++++++++++++++++++++++ src/types.ts | 8 ++++++ 3 files changed, 61 insertions(+) diff --git a/src/ReactHeadSafe.tsx b/src/ReactHeadSafe.tsx index 36a908b..edd4f79 100644 --- a/src/ReactHeadSafe.tsx +++ b/src/ReactHeadSafe.tsx @@ -33,6 +33,7 @@ export const ReactHeadSafe: FC = ({ ogLocale, twitterSite, twitterCreator, + robots, }) => { useLayoutEffect(() => { // Track selectors for meta/link tags inserted in this effect run. @@ -125,6 +126,12 @@ export const ReactHeadSafe: FC = ({ insertedSelectors.push('meta[name="twitter:creator"]'); } + // Update robots meta tag (controls crawler indexing, e.g. "noindex,follow") + if (robots !== undefined) { + updateMetaTag('name', 'robots', robots); + insertedSelectors.push('meta[name="robots"]'); + } + // Cleanup: remove every tag this effect inserted. // - On deps change: runs before the next effect, clearing stale tags // (handles prop → undefined transitions). @@ -148,6 +155,7 @@ export const ReactHeadSafe: FC = ({ ogLocale, twitterSite, twitterCreator, + robots, ]); return null; diff --git a/src/test/ReactHeadSafe.test.tsx b/src/test/ReactHeadSafe.test.tsx index 2fa8729..1023f53 100644 --- a/src/test/ReactHeadSafe.test.tsx +++ b/src/test/ReactHeadSafe.test.tsx @@ -634,6 +634,51 @@ describe('ReactHeadSafe', () => { }); }); + describe('robots meta tag', () => { + it('should create robots meta tag', () => { + render(); + + const metaTag = document.querySelector('meta[name="robots"]'); + expect(metaTag).toBeInTheDocument(); + expect(metaTag?.getAttribute('content')).toBe('noindex,follow'); + }); + + it('should update robots meta tag when prop changes', () => { + const { rerender } = render(); + rerender(); + + const metaTag = document.querySelector('meta[name="robots"]'); + expect(metaTag?.getAttribute('content')).toBe('noindex,nofollow'); + }); + + it('should prevent duplicate robots meta tags', () => { + const { rerender } = render(); + rerender(); + + const metaTags = document.querySelectorAll('meta[name="robots"]'); + expect(metaTags).toHaveLength(1); + expect(metaTags[0].getAttribute('content')).toBe('noindex,nofollow'); + }); + + it('should remove robots meta tag on unmount', () => { + const { unmount } = render(); + unmount(); + + expect( + document.querySelector('meta[name="robots"]') + ).not.toBeInTheDocument(); + }); + + it('should remove robots meta tag when prop becomes undefined', () => { + const { rerender } = render(); + rerender(); + + expect( + document.querySelector('meta[name="robots"]') + ).not.toBeInTheDocument(); + }); + }); + describe('cleanup on unmount', () => { it('should remove all inserted meta and link tags on unmount', () => { const { unmount } = render( diff --git a/src/types.ts b/src/types.ts index ecd9d3b..898ccac 100644 --- a/src/types.ts +++ b/src/types.ts @@ -48,4 +48,12 @@ export interface ReactHeadSafeProps { twitterSite?: string; /** The Twitter @username of the content author (twitter:creator), e.g. "@author" */ twitterCreator?: string; + /** + * The robots meta tag content controlling crawler indexing, e.g. "noindex,follow", "noindex,nofollow". + * + * Note: a JS-injected `noindex` is only honored by crawlers that render JavaScript + * (e.g. Googlebot, with delay). Non-JS crawlers ignore it. For pages that must be + * reliably excluded, use a server-side `X-Robots-Tag: noindex` header instead. + */ + robots?: string; } From 3d8c3998d3604d0e941f5029d3f7c72792bd1917 Mon Sep 17 00:00:00 2001 From: umsungjun Date: Tue, 23 Jun 2026 09:12:40 +0900 Subject: [PATCH 5/6] docs: document robots prop and its noindex limitation in CSR --- README.ko.md | 33 ++++++++++++++++++--------------- README.md | 33 ++++++++++++++++++--------------- 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/README.ko.md b/README.ko.md index a43224f..6cc3fa9 100644 --- a/README.ko.md +++ b/README.ko.md @@ -115,21 +115,24 @@ function MyPage() { ### ReactHeadSafeProps -| Prop | Type | Description | -| ---------------- | -------- | ------------------------------------------------------------------------ | -| `title` | `string` | `document.title`에 설정될 페이지 제목 | -| `description` | `string` | SEO를 위한 메타 설명 태그 콘텐츠 | -| `keywords` | `string` | SEO를 위한 메타 키워드 태그 콘텐츠 | -| `ogTitle` | `string` | 소셜 미디어 공유를 위한 Open Graph 제목 (og:title) | -| `ogDescription` | `string` | 소셜 미디어 공유를 위한 Open Graph 설명 (og:description) | -| `ogImage` | `string` | 소셜 미디어 공유를 위한 Open Graph 이미지 URL (og:image) | -| `ogUrl` | `string` | 소셜 미디어 공유를 위한 Open Graph URL (og:url) | -| `ogType` | `OgType` | Open Graph 타입 (og:type). 표준 12개 값 자동완성 + 임의 string 모두 허용 | -| `canonicalUrl` | `string` | SEO를 위한 페이지의 대표 URL (``) | -| `ogSiteName` | `string` | 소셜 미디어 공유를 위한 사이트 이름 (og:site_name) | -| `ogLocale` | `string` | 콘텐츠의 언어/지역 코드 (og:locale), 예: `"ko_KR"`, `"en_US"` | -| `twitterSite` | `string` | 웹사이트의 Twitter 계정 (twitter:site), 예: `"@mysite"` | -| `twitterCreator` | `string` | 콘텐츠 작성자의 Twitter 계정 (twitter:creator), 예: `"@author"` | +| Prop | Type | Description | +| ---------------- | -------- | -------------------------------------------------------------------------------------------- | +| `title` | `string` | `document.title`에 설정될 페이지 제목 | +| `description` | `string` | SEO를 위한 메타 설명 태그 콘텐츠 | +| `keywords` | `string` | SEO를 위한 메타 키워드 태그 콘텐츠 | +| `ogTitle` | `string` | 소셜 미디어 공유를 위한 Open Graph 제목 (og:title) | +| `ogDescription` | `string` | 소셜 미디어 공유를 위한 Open Graph 설명 (og:description) | +| `ogImage` | `string` | 소셜 미디어 공유를 위한 Open Graph 이미지 URL (og:image) | +| `ogUrl` | `string` | 소셜 미디어 공유를 위한 Open Graph URL (og:url) | +| `ogType` | `OgType` | Open Graph 타입 (og:type). 표준 12개 값 자동완성 + 임의 string 모두 허용 | +| `canonicalUrl` | `string` | SEO를 위한 페이지의 대표 URL (``) | +| `ogSiteName` | `string` | 소셜 미디어 공유를 위한 사이트 이름 (og:site_name) | +| `ogLocale` | `string` | 콘텐츠의 언어/지역 코드 (og:locale), 예: `"ko_KR"`, `"en_US"` | +| `twitterSite` | `string` | 웹사이트의 Twitter 계정 (twitter:site), 예: `"@mysite"` | +| `twitterCreator` | `string` | 콘텐츠 작성자의 Twitter 계정 (twitter:creator), 예: `"@author"` | +| `robots` | `string` | 크롤러 색인을 제어하는 robots 메타 태그 콘텐츠, 예: `"noindex,follow"`, `"noindex,nofollow"` | + +> **주의:** JS로 주입된 `robots="noindex"`는 JavaScript를 렌더링하는 크롤러(예: Googlebot, 단 지연 있음)만 인식합니다. JS를 실행하지 않는 크롤러(상당수의 봇, 소셜 미디어 프리뷰 봇 등)는 이 태그를 무시하므로 페이지가 여전히 색인될 수 있습니다. 반드시 확실하게 색인에서 제외해야 하는 페이지라면, 서버 측 `X-Robots-Tag: noindex` 헤더를 사용하세요. ### Twitter Card 지원 diff --git a/README.md b/README.md index 649d65c..e226d27 100644 --- a/README.md +++ b/README.md @@ -118,21 +118,24 @@ That's it! The component will automatically: ### ReactHeadSafeProps -| Prop | Type | Description | -| ---------------- | -------- | ------------------------------------------------------------------------------------------------ | -| `title` | `string` | The page title that will be set in the `document.title` | -| `description` | `string` | The meta description tag content for SEO | -| `keywords` | `string` | The meta keywords tag content for SEO | -| `ogTitle` | `string` | The Open Graph title (og:title) for social media sharing | -| `ogDescription` | `string` | The Open Graph description (og:description) for social media sharing | -| `ogImage` | `string` | The Open Graph image URL (og:image) for social media sharing | -| `ogUrl` | `string` | The canonical URL of your object that will be used as its permanent ID in the graph (og:url) | -| `ogType` | `OgType` | The type of your object (og:type). Autocompletes 12 standard OG values; also accepts any string. | -| `canonicalUrl` | `string` | The canonical URL of the page for SEO (``) | -| `ogSiteName` | `string` | The site name for social media sharing (og:site_name) | -| `ogLocale` | `string` | The locale of the content (og:locale), e.g. `"en_US"`, `"ko_KR"` | -| `twitterSite` | `string` | The Twitter @username of the website (twitter:site), e.g. `"@mysite"` | -| `twitterCreator` | `string` | The Twitter @username of the content author (twitter:creator), e.g. `"@author"` | +| Prop | Type | Description | +| ---------------- | -------- | ------------------------------------------------------------------------------------------------------- | +| `title` | `string` | The page title that will be set in the `document.title` | +| `description` | `string` | The meta description tag content for SEO | +| `keywords` | `string` | The meta keywords tag content for SEO | +| `ogTitle` | `string` | The Open Graph title (og:title) for social media sharing | +| `ogDescription` | `string` | The Open Graph description (og:description) for social media sharing | +| `ogImage` | `string` | The Open Graph image URL (og:image) for social media sharing | +| `ogUrl` | `string` | The canonical URL of your object that will be used as its permanent ID in the graph (og:url) | +| `ogType` | `OgType` | The type of your object (og:type). Autocompletes 12 standard OG values; also accepts any string. | +| `canonicalUrl` | `string` | The canonical URL of the page for SEO (``) | +| `ogSiteName` | `string` | The site name for social media sharing (og:site_name) | +| `ogLocale` | `string` | The locale of the content (og:locale), e.g. `"en_US"`, `"ko_KR"` | +| `twitterSite` | `string` | The Twitter @username of the website (twitter:site), e.g. `"@mysite"` | +| `twitterCreator` | `string` | The Twitter @username of the content author (twitter:creator), e.g. `"@author"` | +| `robots` | `string` | The robots meta tag content controlling crawler indexing, e.g. `"noindex,follow"`, `"noindex,nofollow"` | + +> **Warning:** A JS-injected `robots="noindex"` is only honored by crawlers that render JavaScript (e.g. Googlebot, with delay). Non-JS crawlers (many bots, social preview crawlers) ignore it, so the page may still be indexed. For pages that must be reliably excluded from indexing, use a server-side `X-Robots-Tag: noindex` header instead. ### Twitter Card Support From 1acd29d43a84adccd78778d6771bb211960843b5 Mon Sep 17 00:00:00 2001 From: umsungjun Date: Tue, 23 Jun 2026 09:12:40 +0900 Subject: [PATCH 6/6] chore: bump version to 1.10.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 931311e..c9d8ee2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "react-head-safe", - "version": "1.9.0", + "version": "1.10.0", "description": "A lightweight React head manager for CSR apps. Safely manage document title, meta tags, Open Graph, and SEO metadata without duplicates. TypeScript support included.", "author": "umsungjun", "license": "MIT",