├── .env.example ├── .eslintrc.json ├── .gitignore ├── .vscode ├── extensions.json └── settings.json ├── README.md ├── app ├── [locale] │ ├── (frontend) │ │ ├── (home) │ │ │ └── page.tsx │ │ ├── [...rest] │ │ │ └── page.tsx │ │ └── layout.tsx │ ├── globals.css │ ├── layout.tsx │ └── not-found.tsx ├── api │ ├── google │ │ └── serp │ │ │ └── route.ts │ ├── layout.tsx │ ├── location │ │ └── route.ts │ └── snapshot │ │ └── [id] │ │ └── route.ts ├── favicon.ico └── robots.ts ├── bin ├── generateComponentsMarkdownData.ts └── watcher.ts ├── components.json ├── components ├── frontend │ ├── google │ │ ├── desktop │ │ │ ├── DownloadCsv.tsx │ │ │ ├── FeaturedSnippets.tsx │ │ │ ├── InlineImages.tsx │ │ │ ├── InlineVideos.tsx │ │ │ ├── LocalResults.tsx │ │ │ ├── PeopleAlsoAsk.tsx │ │ │ ├── Recipes.tsx │ │ │ ├── RelatedSearches.tsx │ │ │ ├── ThinksToKnow.tsx │ │ │ ├── TopStories.tsx │ │ │ ├── Twitter.tsx │ │ │ ├── Video.tsx │ │ │ └── index.tsx │ │ └── shared │ │ │ ├── FilterUrl.tsx │ │ │ ├── ItemNormal.tsx │ │ │ ├── ItemSource.tsx │ │ │ ├── SiteIcon.tsx │ │ │ └── TypeTitle.tsx │ ├── page │ │ └── home │ │ │ ├── faqs.tsx │ │ │ ├── form.tsx │ │ │ ├── landing.tsx │ │ │ ├── main.tsx │ │ │ ├── results.tsx │ │ │ ├── status.tsx │ │ │ └── title-cell.tsx │ └── shared │ │ ├── footer.tsx │ │ ├── header.tsx │ │ ├── nav-bar.tsx │ │ ├── not-found.tsx │ │ └── top.tsx ├── shared │ ├── locale-switch.tsx │ ├── markdown.tsx │ └── mode-toggle.tsx └── ui │ ├── accordion.tsx │ ├── alert-dialog.tsx │ ├── avatar.tsx │ ├── badge.tsx │ ├── button.tsx │ ├── card.tsx │ ├── carousel.tsx │ ├── combobox.tsx │ ├── command.tsx │ ├── dialog.tsx │ ├── dropdown-menu.tsx │ ├── form.tsx │ ├── input.tsx │ ├── label.tsx │ ├── popover.tsx │ ├── select.tsx │ ├── sheet.tsx │ ├── skeleton.tsx │ ├── switch.tsx │ ├── table.tsx │ ├── toast.tsx │ ├── toaster.tsx │ ├── typography.tsx │ └── use-toast.ts ├── config.ts ├── content └── components │ └── home │ ├── block1 │ ├── de.md │ ├── en.md │ ├── es.md │ ├── fr.md │ ├── it.md │ ├── ja.md │ ├── ko.md │ ├── nl.md │ ├── pl.md │ ├── pt.md │ ├── ru.md │ ├── sv.md │ ├── tr.md │ └── zh.md │ └── block2 │ ├── de.md │ ├── en.md │ ├── es.md │ ├── fr.md │ ├── it.md │ ├── ja.md │ ├── ko.md │ ├── nl.md │ ├── pl.md │ ├── pt.md │ ├── ru.md │ ├── sv.md │ ├── tr.md │ └── zh.md ├── country.ts ├── data ├── generated │ └── components-markdown.json └── geotargets.csv ├── i18n.ts ├── image.png ├── language.ts ├── lib ├── api.ts ├── i18n.ts └── utils.ts ├── locales ├── de.json ├── en.json ├── es.json ├── fr.json ├── it.json ├── ja.json ├── ko.json ├── nl.json ├── pl.json ├── ru.json ├── sv.json ├── tr.json └── zh.json ├── middleware.ts ├── models └── GeoTrgets.ts ├── next.config.mjs ├── package-lock.json ├── package.json ├── postcss.config.mjs ├── public ├── apiKey.png ├── logo.png ├── next.svg └── vercel.svg ├── schema └── index.ts ├── tailwind.config.ts └── tsconfig.json /.env.example: -------------------------------------------------------------------------------- 1 | # Get Your API Key: https://www.serp.ing 2 | SERPING_US_EAST_1_API_KEY= -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "next/core-web-vitals", 4 | "eslint:recommended", 5 | "plugin:@typescript-eslint/recommended", 6 | "plugin:react/recommended" 7 | ], 8 | "plugins": [ 9 | "react", 10 | "@typescript-eslint", 11 | "react-hooks" 12 | ], 13 | "rules": { 14 | "react/react-in-jsx-scope": "off", 15 | "react/prop-types": "off", 16 | "@typescript-eslint/no-explicit-any": "warn", 17 | "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }], 18 | "react-hooks/exhaustive-deps": "warn", 19 | "prefer-const": "error", 20 | "react/no-unknown-property": ["error", { "ignore": ["cmdk-input-wrapper"] }], 21 | "@next/next/no-img-element": "off", 22 | "jsx-a11y/alt-text": "off" 23 | }, 24 | "settings": { 25 | "react": { 26 | "version": "detect" 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | .yarn/install-state.gz 8 | 9 | # testing 10 | /coverage 11 | 12 | # next.js 13 | /.next/ 14 | /out/ 15 | 16 | # production 17 | /build 18 | 19 | # misc 20 | .DS_Store 21 | *.pem 22 | 23 | # debug 24 | npm-debug.log* 25 | yarn-debug.log* 26 | yarn-error.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "esbenp.prettier-vscode", 4 | "dbaeumer.vscode-eslint", 5 | "lokalise.i18n-ally", 6 | "bradlc.vscode-tailwindcss" 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.formatOnSave": true, 3 | "editor.codeActionsOnSave": { 4 | "source.organizeImports": "explicit", 5 | "source.fixAll": "explicit" 6 | }, 7 | "tailwindCSS.experimental.classRegex": [ 8 | ["cn\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"] 9 | ], 10 | "typescript.preferences.importModuleSpecifier": "shortest", 11 | "typescript.tsdk": "node_modules/typescript/lib", 12 | "eslint.workingDirectories": [{ "mode": "auto" }], 13 | "eslint.debug": true, 14 | "i18n-ally.localesPaths": ["locales"], 15 | "i18n-ally.keystyle": "nested", 16 | "i18n-ally.enabledFrameworks": ["next-intl"] 17 | } 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SERP Checker 2 | 3 | Analyze SERPs from 230+ Countries with SERP Checking 4 | 5 | SERP Checking offers a powerful, free SERP checker designed to give you comprehensive insights into Google's search engine results pages (SERPs) for any keyword. Our tool stands out with unparalleled global coverage and detailed analysis of SERP features and Rich Results. 6 | 7 | ## Get Your SERP API KEY 8 | 9 | To access the SERP API and start making requests, you'll need your API key. Follow these steps to get your key: 10 | 11 | 1. **Visit the SERP API Website:** 12 | Go to the SERP API website at [SERPING](https://www.serp.ing/) to sign up or log in to your account. 13 | 14 | 2. **Obtain Your API Key:** 15 | After logging in, navigate to the [API section](https://www.serp.ing/app/settings/team/tokens) or dashboard to find your unique API key. This key will be required to authenticate your API requests. 16 | 17 | 18 | ![Get SERPING API KEY](public/apiKey.png) 19 | 20 | 3. **Use Your API Key:** 21 | Once you have your API key, you can use it in your requests to the SERP API. Set the key in your environment variable or directly in your code as shown below: 22 | 23 | 24 | ```sh 25 | SERPING_US_EAST_1_API_KEY=your_serping_api_key 26 | ``` 27 | 28 | ## Getting Started 29 | 30 | First, run the development server: 31 | 32 | ```bash 33 | npm run dev 34 | # or 35 | yarn dev 36 | # or 37 | pnpm dev 38 | # or 39 | bun dev 40 | ``` 41 | 42 | ## Learn More 43 | 44 | To learn more about Next.js, take a look at the following resources: 45 | 46 | - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. 47 | - [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. 48 | 49 | You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome! 50 | 51 | ## Deploy on Vercel 52 | 53 | You can deploy this project to Vercel with the following button: 54 | 55 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/import/project?template=https://github.com/serping/serp-checker) 56 | -------------------------------------------------------------------------------- /app/[locale]/(frontend)/(home)/page.tsx: -------------------------------------------------------------------------------- 1 | 2 | import { LocaleType } from "@/config"; 3 | import { Main } from "@/frontend/page/home/main"; 4 | import { getComponentMarkdown } from "@/i18n"; 5 | 6 | export default function Home({ 7 | params 8 | }: Readonly<{ 9 | params: { locale: string; }; 10 | }>) { 11 | // Load by key: data/generated/components-markdown.json 12 | const markdownContents = { 13 | block1: getComponentMarkdown({ 14 | locale: params.locale as LocaleType, 15 | componentPathName: "home/block1" 16 | }), 17 | block2: getComponentMarkdown({ 18 | locale: params.locale as LocaleType, 19 | componentPathName: "home/block2" 20 | }), 21 | } 22 | return ( 23 |
24 |
25 |
26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /app/[locale]/(frontend)/[...rest]/page.tsx: -------------------------------------------------------------------------------- 1 | import { NotFound } from "@/frontend/shared/not-found"; 2 | 3 | export default function NotFoundPage() { 4 | return ; 5 | } 6 | -------------------------------------------------------------------------------- /app/[locale]/(frontend)/layout.tsx: -------------------------------------------------------------------------------- 1 | import { Footer } from "@/frontend/shared/footer"; 2 | import { Header } from "@/frontend/shared/header"; 3 | import { Top } from "@/frontend/shared/top"; 4 | import type { PropsWithChildren } from "react"; 5 | 6 | export default function FrontendLayout({ children }: PropsWithChildren) { 7 | return ( 8 | <> 9 |
10 |
11 | {children} 12 |
13 |