<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Raj Chavan</title>
    <description>The latest articles on DEV Community by Raj Chavan (@raj_chavan524).</description>
    <link>https://dev.to/raj_chavan524</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3972564%2Faba07d1a-33cc-4279-b587-c375ec945368.jpeg</url>
      <title>DEV Community: Raj Chavan</title>
      <link>https://dev.to/raj_chavan524</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/raj_chavan524"/>
    <language>en</language>
    <item>
      <title>I built an app that OCRs every screenshot on your phone — here's the architecture</title>
      <dc:creator>Raj Chavan</dc:creator>
      <pubDate>Thu, 13 Aug 2026 06:13:46 +0000</pubDate>
      <link>https://dev.to/raj_chavan524/i-built-an-app-that-ocrs-every-screenshot-on-your-phone-heres-the-architecture-2ik3</link>
      <guid>https://dev.to/raj_chavan524/i-built-an-app-that-ocrs-every-screenshot-on-your-phone-heres-the-architecture-2ik3</guid>
      <description>&lt;p&gt;We all have that folder of 500+ screenshots we can never find anything in. I got tired of scrolling through mine looking for a receipt from three months ago, so I built Screenshot Vault — an app that reads the text in every screenshot on your phone and lets you search it like Google.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Here's how it's built, and a few decisions that ended up mattering more than I expected.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The stack&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Expo (React Native) + Expo Router — file-based routing, EAS for native builds&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;@react-native-ml-kit/text-recognition — on-device OCR via Google ML Kit&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;expo-sqlite — local persistence&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;expo-media-library — reading the device's Screenshots album&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Gemini 3.6 Flash — categorization, titles, tags, called through a small Next.js API route&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Next.js + Vercel — landing page + the backend proxy&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Decision #1&lt;/strong&gt;: &lt;strong&gt;&lt;em&gt;OCR stays fully on-device&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;My first instinct was to upload screenshots to a server for processing. Then I actually thought about what's in a typical screenshot folder — bank OTPs, payment confirmations, private chats, addresses. Uploading that to a database I control is a liability for me and a real risk for users if anything ever leaks.&lt;/p&gt;

&lt;p&gt;Google ML Kit's text recognition runs entirely on-device, for free, with no server round-trip. So OCR happens locally, and the only thing that ever leaves the phone is the already-extracted text — sent to Gemini for a lightweight categorization call, not the image itself. This also happens to be cheaper to run at scale, since I'm not paying for image storage or bandwidth.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision #2&lt;/strong&gt;: &lt;em&gt;&lt;strong&gt;Don't block the user on a full scan&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If someone installs this with 500 existing screenshots, running OCR + AI on all of them before showing anything would mean a 10-20 minute wait on first launch. That's an instant uninstall.&lt;/p&gt;

&lt;p&gt;Instead, processing is staged and resumable:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;CREATE&lt;/span&gt; &lt;span class="nx"&gt;TABLE&lt;/span&gt; &lt;span class="nf"&gt;screenshots &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="nx"&gt;TEXT&lt;/span&gt; &lt;span class="nx"&gt;PRIMARY&lt;/span&gt; &lt;span class="nx"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;uri&lt;/span&gt; &lt;span class="nx"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;text_content&lt;/span&gt; &lt;span class="nx"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;category&lt;/span&gt; &lt;span class="nx"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ai_title&lt;/span&gt; &lt;span class="nx"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;tags&lt;/span&gt; &lt;span class="nx"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ocr_done&lt;/span&gt; &lt;span class="nx"&gt;INTEGER&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;ai_done&lt;/span&gt; &lt;span class="nx"&gt;INTEGER&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;created_at&lt;/span&gt; &lt;span class="nx"&gt;INTEGER&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;On open:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Show whatever's already in SQLite — instant, zero wait&lt;/li&gt;
&lt;li&gt;Insert bare rows for any new screenshots found (thumbnail visible immediately)&lt;/li&gt;
&lt;li&gt;Background pass: OCR everything with ocr_done = 0, newest-first&lt;/li&gt;
&lt;li&gt;Background pass: AI-classify everything with ocr_done = 1 AND ai_done = 0, newest-first&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;If the app gets closed mid-scan&lt;/em&gt;, &lt;strong&gt;it just picks up from wherever the flags left off next time&lt;/strong&gt; — no reprocessing, no lost work. This is basically the same idea Google Photos uses for its "preparing your library" background indexing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Decision #3&lt;/strong&gt;:&lt;strong&gt;_ Never put the AI API key in the client_&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Early version called Gemini directly from the app with the key in an env var. Realized pretty quickly that anyone who installs the APK can extract that key and rack up usage on my bill — env vars prefixed EXPO_PUBLIC_ get bundled straight into the client, no exceptions.&lt;/p&gt;

&lt;p&gt;Moved it behind a single Next.js API route on the same Vercel project as the landing page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;NextRequest&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GEMINI_API_KEY&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// server-only, never shipped to client&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;GEMINI_ENDPOINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;x-goog-api-key&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;apiKey&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="cm"&gt;/* prompt asking for category + title + tags in one call */&lt;/span&gt; &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="c1"&gt;// ...parse and return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One call returns category + title + tags together instead of three separate requests — matters a lot on Gemini's free tier, which caps out fast.&lt;/p&gt;

&lt;p&gt;Still early and Android-only right now, testing with a small group before a wider release. If you want to follow along or try it when it's ready: screenshot-vault-lac.vercel.app&lt;/p&gt;

&lt;p&gt;Curious if anyone's tackled similar on-device vs. cloud tradeoffs for AI features — happy to talk through any of this in the comments.&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>android</category>
      <category>buildinpublic</category>
      <category>ai</category>
    </item>
    <item>
      <title>I Open-Sourced the SDK Behind My SaaS — Here's Why</title>
      <dc:creator>Raj Chavan</dc:creator>
      <pubDate>Tue, 21 Jul 2026 06:40:42 +0000</pubDate>
      <link>https://dev.to/raj_chavan524/i-open-sourced-the-sdk-behind-my-saas-heres-why-1e8h</link>
      <guid>https://dev.to/raj_chavan524/i-open-sourced-the-sdk-behind-my-saas-heres-why-1e8h</guid>
      <description>&lt;p&gt;I've been building TourKit for the past 3 months — a product tour SDK for SaaS products.&lt;/p&gt;

&lt;p&gt;One script tag. Dashboard-controlled tours.&lt;br&gt;
Works on React, Next.js, Vue, HTML, WordPress.&lt;/p&gt;

&lt;p&gt;Today I open-sourced the SDK under an MIT license.&lt;/p&gt;

&lt;p&gt;Here's why and what's inside.&lt;/p&gt;


&lt;h2&gt;
  
  
  The problem with closed-source SDKs
&lt;/h2&gt;

&lt;p&gt;When you install a third-party script on your website, you're trusting that it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Doesn't track your users beyond what it says&lt;/li&gt;
&lt;li&gt;Doesn't inject anything malicious&lt;/li&gt;
&lt;li&gt;Does exactly what it claims to do&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With a closed-source SDK, you have to take the company's word for it.&lt;/p&gt;

&lt;p&gt;That's a hard sell for security-conscious developers — especially when the script runs on every page of their product.&lt;/p&gt;


&lt;h2&gt;
  
  
  So I open-sourced it
&lt;/h2&gt;

&lt;p&gt;The TourKit SDK is now public and MIT-licensed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://github.com/webdev-raj/Tourkit-sdk" rel="noopener noreferrer"&gt;github.com/webdev-raj/Tourkit-sdk&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You can read every line of code that runs on your users' websites. Audit it. Fork it. Self-host it if you want.&lt;/p&gt;


&lt;h2&gt;
  
  
  What's inside the SDK
&lt;/h2&gt;

&lt;p&gt;The SDK is vanilla JavaScript with zero dependencies. Here's what it does:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;index.js — Config fetcher&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Reads data-key from script tag&lt;/span&gt;
&lt;span class="c1"&gt;// Fetches tour config from TourKit API&lt;/span&gt;
&lt;span class="c1"&gt;// Calls startTour() with steps + config&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TourKit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;startFor&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;resetAll&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;renderer.js — Tooltip engine&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates spotlight overlay&lt;/li&gt;
&lt;li&gt;Positions tooltip (top/bottom/left/right)&lt;/li&gt;
&lt;li&gt;Handles step transitions&lt;/li&gt;
&lt;li&gt;Mobile bottom sheet under 768px&lt;/li&gt;
&lt;li&gt;Tracks analytics events&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;session-key.js — Seen flag management&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Per-path localStorage keys&lt;/span&gt;
&lt;span class="c1"&gt;// tourkit_seen_KEY_dashboard&lt;/span&gt;
&lt;span class="c1"&gt;// tourkit_seen_KEY_projects&lt;/span&gt;
&lt;span class="c1"&gt;// Each page independent&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The mobile bottom sheet
&lt;/h2&gt;

&lt;p&gt;This is the part I'm most proud of.&lt;/p&gt;

&lt;p&gt;Every other tour SDK breaks on mobile.&lt;br&gt;
Intercom literally doesn't support mobile product tours — their docs say so.&lt;/p&gt;

&lt;p&gt;TourKit automatically switches to bottom sheet mode on screens under 768px:&lt;/p&gt;

&lt;p&gt;Desktop (768px+):&lt;br&gt;
Tooltip floats beside highlighted element&lt;/p&gt;

&lt;p&gt;Mobile (under 768px):&lt;br&gt;
Element highlighted at top of screen&lt;br&gt;
Tooltip slides up from the bottom&lt;br&gt;
Feels completely native&lt;/p&gt;

&lt;p&gt;Zero config. SDK detects screen size and switches automatically.&lt;/p&gt;


&lt;h2&gt;
  
  
  URL-based tour triggers
&lt;/h2&gt;

&lt;p&gt;Each step can target a specific page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Your projects"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Manage all your projects here"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"selector"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"[data-tourkit='projects-list']"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"position"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"bottom"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"url_pattern"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/dashboard/projects"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pattern matching supports:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Exact: &lt;code&gt;/dashboard&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Dynamic: &lt;code&gt;/dashboard/projects/[id]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Wildcard: &lt;code&gt;/dashboard/*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;All pages: &lt;code&gt;null&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The SDK checks &lt;code&gt;window.location.pathname&lt;/code&gt;on every route change and starts the tour from the matching step automatically.&lt;/p&gt;




&lt;h2&gt;
  
  
  The AI workflow (the real differentiator)
&lt;/h2&gt;

&lt;p&gt;This is what makes TourKit different from every other tour tool:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1 — Copy the AI prompt&lt;/strong&gt;&lt;br&gt;
From your TourKit dashboard, copy the agent prompt with one click.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2 — Paste into Cursor&lt;/strong&gt;&lt;br&gt;
Your AI agent:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reads your entire codebase&lt;/li&gt;
&lt;li&gt;Identifies key UI elements&lt;/li&gt;
&lt;li&gt;Adds data-tourkit attributes&lt;/li&gt;
&lt;li&gt;Detects your routes automatically&lt;/li&gt;
&lt;li&gt;Generates tour.json with correct 
url_patterns for each page&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Step 3 — Drag and drop&lt;/strong&gt;&lt;br&gt;
Drop tour.json into the TourKit dashboard. All steps import instantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 4 — Add script tag once&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script
  &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/gh/webdev-raj/Tourkit-sdk@v1.0.0/dist/tourkit.min.js"&lt;/span&gt;
  &lt;span class="na"&gt;data-key=&lt;/span&gt;&lt;span class="s"&gt;"YOUR_KEY"&lt;/span&gt;
  &lt;span class="na"&gt;data-api=&lt;/span&gt;&lt;span class="s"&gt;"https://tourkit-phi.vercel.app"&lt;/span&gt;
  &lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Live tour in under 2 minutes.&lt;br&gt;
No manual CSS selectors.&lt;br&gt;
No guessing which elements to highlight.&lt;/p&gt;




&lt;h2&gt;
  
  
  The open core model
&lt;/h2&gt;

&lt;p&gt;Dashboard stays private.&lt;br&gt;
SDK is open source.&lt;/p&gt;

&lt;p&gt;Same model as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Plausible Analytics&lt;/li&gt;
&lt;li&gt;Cal.com&lt;/li&gt;
&lt;li&gt;Supabase&lt;/li&gt;
&lt;li&gt;Fathom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The SDK is the delivery mechanism.&lt;br&gt;
The dashboard is where the value lives — step editor, analytics, AI generator, prebuilt templates, team management.&lt;/p&gt;




&lt;h2&gt;
  
  
  Current honest status
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;✅ SDK open source + MIT licensed&lt;/li&gt;
&lt;li&gt;✅ Working on React, Next.js, Vue, HTML&lt;/li&gt;
&lt;li&gt;✅ Mobile bottom sheet tours&lt;/li&gt;
&lt;li&gt;✅ AI tour generator&lt;/li&gt;
&lt;li&gt;✅ JSON drag and drop import&lt;/li&gt;
&lt;li&gt;✅ Analytics dashboard&lt;/li&gt;
&lt;li&gt;❌ 0 paying customers&lt;/li&gt;
&lt;li&gt;❌ npm package (coming soon)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Try it
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Dashboard (free plan available):&lt;/strong&gt;&lt;br&gt;
tourkit-phi.vercel.app&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Open source SDK:&lt;/strong&gt;&lt;br&gt;
github.com/webdev-raj/Tourkit-sdk&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Docs:&lt;/strong&gt;&lt;br&gt;
tourkit-phi.vercel.app/docs&lt;/p&gt;




&lt;p&gt;If you're building a SaaS and need user onboarding — I'd genuinely love for you to try it and tell me what's broken or missing.&lt;/p&gt;

&lt;p&gt;And if you find the SDK useful — a GitHub star genuinely helps with &lt;br&gt;
discovery 🙏&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Building in public. 3 months in. 0 paying customers. Shipping every week.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>saas</category>
      <category>javascript</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Stop losing users in the first 5 minutes — onboarding problem for indie SaaS</title>
      <dc:creator>Raj Chavan</dc:creator>
      <pubDate>Sat, 04 Jul 2026 15:06:33 +0000</pubDate>
      <link>https://dev.to/raj_chavan524/stop-losing-users-in-the-first-5-minutes-onboarding-problem-for-indie-saas-ihk</link>
      <guid>https://dev.to/raj_chavan524/stop-losing-users-in-the-first-5-minutes-onboarding-problem-for-indie-saas-ihk</guid>
      <description>&lt;p&gt;&lt;strong&gt;Every SaaS Product has the same silent killer&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;User signs up. Lands on your dashboard.&lt;br&gt;
Looks around. Gets confused. Leaves.&lt;/p&gt;

&lt;p&gt;You never hear from them again.&lt;br&gt;
No error. No complaint. Just gone.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The brutal math:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If 100 people sign up and 70 leave in the first session without understanding your product, you're not growing; you're filling a leaky bucket.&lt;/p&gt;

&lt;p&gt;Better onboarding doesn't just improve retention. It makes everything else work better too.&lt;/p&gt;

&lt;p&gt;Better onboarding → more activated users&lt;br&gt;
More activated users → more upgrades&lt;br&gt;
More upgrades → more word of mouth&lt;br&gt;
More word of mouth → more signups&lt;/p&gt;

&lt;p&gt;It compounds.&lt;/p&gt;

&lt;p&gt;The problem with existing solutions:&lt;/p&gt;

&lt;p&gt;Intercom Product Tours — $300+/month minimum. Not a conversation for anyone bootstrapping.&lt;/p&gt;

&lt;p&gt;Intro.js / Shepherd.js — free but you write hundreds of lines of JavaScript config. Update one CSS class, and it silently breaks in production. Zero error messages.&lt;/p&gt;

&lt;p&gt;There was nothing in between for indie hackers.&lt;/p&gt;

&lt;p&gt;What TourKit does:&lt;/p&gt;

&lt;p&gt;Paste one script tag on your website. Configure tour steps from a dashboard.&lt;br&gt;
Visitors get a guided walkthrough automatically.&lt;/p&gt;

&lt;p&gt;No code. No framework lock-in. No complex setup.&lt;/p&gt;

&lt;p&gt;What you get:&lt;br&gt;
→ New users understand your product faster&lt;br&gt;
→ Less support questions about basic features&lt;br&gt;
→ Higher activation rate in first session&lt;br&gt;
→ Analytics showing exactly where users drop off&lt;br&gt;
→ Tours that work on mobile with bottom sheet UI&lt;br&gt;
→ Context-aware tours — different steps per page&lt;/p&gt;

&lt;p&gt;What it costs:&lt;br&gt;
→ &lt;em&gt;Free tier to start&lt;/em&gt;&lt;br&gt;
→ &lt;em&gt;$9/month for growing products&lt;/em&gt;&lt;br&gt;
→ &lt;em&gt;$19/month for unlimited everything + AI generator&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;vs &lt;strong&gt;Intercom at $300+/month.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The outcome in plain terms:&lt;/p&gt;

&lt;p&gt;Your users stop leaving confused. They start understanding your product.&lt;br&gt;
They stick around long enough to see the value.&lt;/p&gt;

&lt;p&gt;That's the whole point.&lt;/p&gt;

&lt;p&gt;If you're building a SaaS and onboarding is currently "signup → blank dashboard → hope they figure it out" — that's fixable.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tourkit-phi.vercel.app" rel="noopener noreferrer"&gt;try here tourkit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Curious — what does your current onboarding look like? Email sequence, video walkthrough, in-app tour, or nothing at all?&lt;/p&gt;

</description>
      <category>saas</category>
      <category>onboarding</category>
      <category>problemsolve</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Why I built an onboarding tool instead of using Intercom (and what it cost me)</title>
      <dc:creator>Raj Chavan</dc:creator>
      <pubDate>Tue, 30 Jun 2026 13:27:40 +0000</pubDate>
      <link>https://dev.to/raj_chavan524/why-i-built-an-onboarding-tool-instead-of-using-intercom-and-what-it-cost-me-ea2</link>
      <guid>https://dev.to/raj_chavan524/why-i-built-an-onboarding-tool-instead-of-using-intercom-and-what-it-cost-me-ea2</guid>
      <description>&lt;p&gt;I spent three months building TourKit. Here's the honest story of&lt;br&gt;
why, and what it actually cost me to build it solo.&lt;/p&gt;
&lt;h2&gt;
  
  
  The problem I kept hitting
&lt;/h2&gt;

&lt;p&gt;Every side project I built had the same issue. Users would sign up, land on the dashboard, look around confused, and leave.&lt;/p&gt;

&lt;p&gt;No onboarding. No guidance. Just a blank page and hope they figure it out.&lt;/p&gt;

&lt;p&gt;I knew the fix existed — product tours. The little tooltips that walk you through a new app. I'd used them on Notion, Linear, Vercel. They work.&lt;/p&gt;

&lt;p&gt;So I went looking for a tool to add one to my own project.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I found
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Intercom Product Tours&lt;/strong&gt; — the industry standard. Opened their pricing page. $300+/month minimum to get product tours. For a side project making $0, that's not a discussion; that's a no.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Appcues&lt;/strong&gt; — similar story. $300-500/month. Enterprise pricing for an enterprise problem I didn't have.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Intro.js&lt;/strong&gt; — free and open source. This seemed promising until I actually tried to use it. You write JavaScript config for every single step. No dashboard. No analytics. Update a CSS class and&lt;br&gt;
your tour silently breaks in production.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Shepherd.js&lt;/strong&gt; — same category as Intro.js. More flexible, still requires real code, still no dashboard or analytics.&lt;/p&gt;

&lt;p&gt;I needed something between "$300/month enterprise tool" and "write 200 lines of JS yourself."&lt;/p&gt;

&lt;p&gt;It didn't exist. So I decided to build it.&lt;/p&gt;
&lt;h2&gt;
  
  
  What I actually built
&lt;/h2&gt;

&lt;p&gt;TourKit — paste one script tag on your website, configure tour steps from a dashboard, your visitors get a guided walkthrough.&lt;/p&gt;

&lt;p&gt;The core idea: give indie hackers and small teams the dashboard experience of Intercom without the enterprise price tag.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script
  &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/gh/webdev-raj/Tourkit@sdk-v14/sdk/dist/tourkit.min.js"&lt;/span&gt;
  &lt;span class="na"&gt;data-key=&lt;/span&gt;&lt;span class="s"&gt;"YOUR_KEY"&lt;/span&gt;
  &lt;span class="na"&gt;data-api=&lt;/span&gt;&lt;span class="s"&gt;"https://tourkit-phi.vercel.app"&lt;/span&gt;
  &lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That's the entire installation. Everything else happens in the dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it cost me to build
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Time:&lt;/strong&gt; Roughly 3 months of evenings and weekends, solo, using Cursor heavily for the actual coding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Money:&lt;/strong&gt; Almost nothing. The whole stack runs on free tiers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Vercel (hosting) — free&lt;/li&gt;
&lt;li&gt;Supabase (database, auth) — free tier&lt;/li&gt;
&lt;li&gt;jsDelivr (CDN for the SDK) — free&lt;/li&gt;
&lt;li&gt;Lemon Squeezy (payments) — free + 5% fee&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total monthly infrastructure cost right now: $0.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mistakes:&lt;/strong&gt; A lot. I spent way too long polishing animations before I even had basic payments working. I built features nobody asked for because building felt more productive than the scarier task of actually trying to get customers.&lt;/p&gt;

&lt;h2&gt;
  
  
  The hardest technical problem
&lt;/h2&gt;

&lt;p&gt;Context-aware tours on dynamic URLs. If your app has routes like &lt;code&gt;/products/[id]&lt;/code&gt;, a naive URL matcher either matches every product page with the same tour (annoying, repeats forever) or matches nothing at all.&lt;/p&gt;

&lt;p&gt;I ended up building pattern-based matching:&lt;/p&gt;

&lt;p&gt;/products/[id] matches /products/123&lt;br&gt;
/products/[id] matches /products/456&lt;/p&gt;

&lt;p&gt;Both share the same "seen" flag, based on the pattern, not the actual URL. So the tour shows once across all product pages, not once per product.&lt;/p&gt;

&lt;p&gt;This took multiple rebuilds to get right, including finding the bug by literally adding TourKit to my own TourKit dashboard and using it myself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Dogfooding finds bugs nothing else does.&lt;/strong&gt; I added TourKit's own tours to TourKit's own dashboard and found three critical matching bugs in 24 hours that months of manual testing missed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Free tier infrastructure goes a long way.&lt;/strong&gt; This entire SaaS, including a vanilla JS SDK, dashboard, analytics, and payments, costs $0/month to run at small scale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Building is the easy part.&lt;/strong&gt; I can ship features fast. Getting someone to actually pay $9/month is the part I'm still figuring out.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where it's at now
&lt;/h2&gt;

&lt;p&gt;TourKit is live and functional. Free tier, plus paid plans starting at $9/month. Still working on getting the first real paying customers — turns out that's a different skill than writing code.&lt;/p&gt;

&lt;p&gt;If you're building a SaaS and onboarding is an afterthought, it shouldn't be. Whether you use TourKit or build your own, that first impression matters more than most features you'll ship.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://tourkit-phi.vercel.app" rel="noopener noreferrer"&gt;tourkit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Happy to answer questions about the technical side,&lt;br&gt;
the stack, or just the experience of building solo.&lt;/p&gt;

</description>
      <category>saas</category>
      <category>webdev</category>
      <category>indiehackers</category>
      <category>buildinpublic</category>
    </item>
    <item>
      <title>Building a Context-Aware Onboarding System in Next.js</title>
      <dc:creator>Raj Chavan</dc:creator>
      <pubDate>Tue, 09 Jun 2026 16:17:35 +0000</pubDate>
      <link>https://dev.to/raj_chavan524/building-a-context-aware-onboarding-system-in-nextjs-4jin</link>
      <guid>https://dev.to/raj_chavan524/building-a-context-aware-onboarding-system-in-nextjs-4jin</guid>
      <description>&lt;p&gt;When I started building TourKit, I thought onboarding tours would be the easy part.&lt;/p&gt;

&lt;p&gt;Create a few tooltips, highlight some elements, and move users from step to step.&lt;/p&gt;

&lt;p&gt;Turns out I was completely wrong.&lt;/p&gt;

&lt;p&gt;The real challenge wasn't building the UI.&lt;/p&gt;

&lt;p&gt;It was deciding when a tour should start.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem with Traditional Tours
&lt;/h2&gt;

&lt;p&gt;Most onboarding systems follow a fixed flow:&lt;/p&gt;

&lt;p&gt;Dashboard → Analytics → Settings → Complete&lt;/p&gt;

&lt;p&gt;But real users don't behave like that.&lt;/p&gt;

&lt;p&gt;Some users land directly on the analytics page.&lt;/p&gt;

&lt;p&gt;Others skip half the product and jump straight into settings.&lt;/p&gt;

&lt;p&gt;Showing the same onboarding flow to everyone creates friction instead of helping.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Goal
&lt;/h2&gt;

&lt;p&gt;I wanted onboarding to react to where users actually are.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User lands on &lt;code&gt;/analytics&lt;/code&gt; → show analytics onboarding&lt;/li&gt;
&lt;li&gt;User lands on &lt;code&gt;/settings&lt;/code&gt; →  show settings onboarding&lt;/li&gt;
&lt;li&gt;User opens a feature for the first time → explain only that feature&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Instead of forcing users through a long tutorial, the onboarding should feel contextual.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Technical Challenge
&lt;/h2&gt;

&lt;p&gt;The difficult part wasn't rendering tooltips.&lt;/p&gt;

&lt;p&gt;It was handling:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Route changes&lt;/li&gt;
&lt;li&gt;Delayed component rendering&lt;/li&gt;
&lt;li&gt;Missing elements&lt;/li&gt;
&lt;li&gt;Dynamic page content&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A tour could start before the target element even existed in the DOM.&lt;/p&gt;

&lt;p&gt;This caused selectors to fail and onboarding to break.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Solution
&lt;/h2&gt;

&lt;p&gt;I built a trigger system that waits for specific conditions before launching a tour.&lt;/p&gt;

&lt;p&gt;Example triggers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;URL-based&lt;/li&gt;
&lt;li&gt;First visit based&lt;/li&gt;
&lt;li&gt;Feature interaction-based&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This allowed onboarding to adapt naturally to user behavior.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;The UI is often the easiest part of onboarding.&lt;/p&gt;

&lt;p&gt;The real complexity lives in runtime behavior:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Knowing when to start&lt;/li&gt;
&lt;li&gt;Knowing what to show&lt;/li&gt;
&lt;li&gt;Avoiding interruption&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The best onboarding doesn't force users through a tutorial.&lt;/p&gt;

&lt;p&gt;It helps them make progress.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;Building this feature took far longer than I expected, but it completely changed how I think about onboarding.&lt;/p&gt;

&lt;p&gt;Users don't want more steps.&lt;/p&gt;

&lt;p&gt;They want momentum.&lt;/p&gt;

&lt;p&gt;I'm currently building TourKit, a developer-first onboarding platform focused on lightweight and contextual onboarding experiences.&lt;/p&gt;

&lt;p&gt;Try it out - here - &lt;a href="https://tourkit-phi.vercel.app" rel="noopener noreferrer"&gt;Tourkit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Would love to hear how others are approaching onboarding in their products.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>nextjs</category>
      <category>buildinpublic</category>
      <category>saas</category>
    </item>
    <item>
      <title>Add an onboarding tour to any React/Next.js app in 5 minutes</title>
      <dc:creator>Raj Chavan</dc:creator>
      <pubDate>Sun, 07 Jun 2026 15:17:14 +0000</pubDate>
      <link>https://dev.to/raj_chavan524/add-an-onboarding-tour-to-any-reactnextjs-app-in-5-minutes-2i70</link>
      <guid>https://dev.to/raj_chavan524/add-an-onboarding-tour-to-any-reactnextjs-app-in-5-minutes-2i70</guid>
      <description>&lt;h1&gt;
  
  
  Add an onboarding tour to any React/Next.js app in 5 minutes
&lt;/h1&gt;

&lt;p&gt;Most apps have zero onboarding.&lt;/p&gt;

&lt;p&gt;Users land on your dashboard, look around confused, and leave.&lt;/p&gt;

&lt;p&gt;The problem? Existing tools like Intercom cost $300+/month. Shepherd.js requires writing hundreds of lines of config. Intro.js feels outdated.&lt;/p&gt;

&lt;p&gt;I built TourKit to fix this. One script tag. Configure from a dashboard. Works on any website.&lt;/p&gt;

&lt;p&gt;Here's how to add it to your React or Next.js app in 5 minutes.&lt;/p&gt;




&lt;h2&gt;
  
  
  What you'll build
&lt;/h2&gt;

&lt;p&gt;A guided onboarding tour that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Highlights specific elements on your page&lt;/li&gt;
&lt;li&gt;Shows tooltips with title and message&lt;/li&gt;
&lt;li&gt;Tracks completion in analytics&lt;/li&gt;
&lt;li&gt;Never repeats for returning users&lt;/li&gt;
&lt;li&gt;Works on mobile with bottom sheet UI&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Step 1 — Create a free account
&lt;/h2&gt;

&lt;p&gt;Go to tourkit-phi.vercel.app and sign up.&lt;/p&gt;

&lt;p&gt;Create a new project:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Project name: My App&lt;/li&gt;
&lt;li&gt;Domain: yourapp.com&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll get a unique script key. Copy it.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 2 — Install the script tag
&lt;/h2&gt;

&lt;h3&gt;
  
  
  For Next.js (App Router)
&lt;/h3&gt;

&lt;p&gt;Add to your root &lt;code&gt;app/layout.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Script&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Script&lt;/span&gt;
          &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/gh/webdev-raj/Tourkit@sdk-v13/sdk/dist/tourkit.min.js"&lt;/span&gt;
          &lt;span class="na"&gt;data-key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"YOUR_SCRIPT_KEY"&lt;/span&gt;
          &lt;span class="na"&gt;data-api&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://tourkit-phi.vercel.app"&lt;/span&gt;
          &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"afterInteractive"&lt;/span&gt;
        &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  For React (Create React App / Vite)
&lt;/h3&gt;

&lt;p&gt;Add to your &lt;code&gt;public/index.html&lt;/code&gt; before &lt;code&gt;&amp;lt;/body&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;script
  &lt;/span&gt;&lt;span class="na"&gt;src=&lt;/span&gt;&lt;span class="s"&gt;"https://cdn.jsdelivr.net/gh/webdev-raj/Tourkit@sdk-v13/sdk/dist/tourkit.min.js"&lt;/span&gt;
  &lt;span class="na"&gt;data-key=&lt;/span&gt;&lt;span class="s"&gt;"YOUR_SCRIPT_KEY"&lt;/span&gt;
  &lt;span class="na"&gt;data-api=&lt;/span&gt;&lt;span class="s"&gt;"https://tourkit-phi.vercel.app"&lt;/span&gt;
  &lt;span class="na"&gt;async&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;YOUR_SCRIPT_KEY&lt;/code&gt; with the key from your TourKit dashboard.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step 3 — Add TourKitProvider for route changes
&lt;/h2&gt;

&lt;p&gt;React and Next.js use client-side routing. The page URL changes without a full reload.&lt;/p&gt;

&lt;p&gt;Without this, TourKit only runs on initial page load and misses route changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Next.js (App Router)
&lt;/h3&gt;

&lt;p&gt;Create &lt;code&gt;components/TourKitProvider.jsx&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;use client&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;usePathname&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;next/navigation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TourKitProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;usePathname&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TourKit&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;startFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add to &lt;code&gt;app/layout.js&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;TourKitProvider&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@/components/TourKitProvider&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;RootLayout&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TourKitProvider&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Script&lt;/span&gt; &lt;span class="err"&gt;...&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;body&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;html&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  React Router
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useEffect&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useLocation&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-router-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;TourKitProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useLocation&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

  &lt;span class="nf"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;timer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TourKit&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="nf"&gt;startFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;clearTimeout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;timer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add inside your &lt;code&gt;&amp;lt;BrowserRouter&amp;gt;&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BrowserRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;TourKitProvider&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;App&lt;/span&gt; &lt;span class="p"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;BrowserRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Step 4 — Configure your tour steps
&lt;/h2&gt;

&lt;p&gt;Go back to your TourKit dashboard.&lt;/p&gt;

&lt;p&gt;Open your project → click Edit Tour.&lt;/p&gt;

&lt;p&gt;Add your first step:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Title:&lt;/strong&gt; Welcome to MyApp&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Message:&lt;/strong&gt; This is your main dashboard 
where you manage everything.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS Selector:&lt;/strong&gt; .dashboard-header&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Position:&lt;/strong&gt; bottom&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add more steps for key features:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: .dashboard-header → "Welcome to MyApp"&lt;br&gt;
&lt;strong&gt;Step 2&lt;/strong&gt;: .sidebar-nav → "Navigate between sections here"&lt;br&gt;
&lt;strong&gt;Step 3&lt;/strong&gt;: .create-btn → "Click here to create your first item"&lt;br&gt;
&lt;strong&gt;Step 4&lt;/strong&gt;: .settings-link → "Customize your account here"&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Finding the right CSS selector:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open Chrome DevTools (F12) → right click any element → Inspect → copy the selector.&lt;/p&gt;

&lt;p&gt;Common selectors:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;nav&lt;/strong&gt;           → navigation bar&lt;br&gt;
&lt;strong&gt;.sidebar&lt;/strong&gt;      → sidebar&lt;br&gt;
&lt;strong&gt;#dashboard&lt;/strong&gt;    → element with id="dashboard"&lt;br&gt;
&lt;strong&gt;.btn-primary&lt;/strong&gt;  → primary button&lt;br&gt;
&lt;strong&gt;header&lt;/strong&gt;        → page header&lt;/p&gt;


&lt;h2&gt;
  
  
  Step 5 — Test your tour
&lt;/h2&gt;

&lt;p&gt;Click &lt;strong&gt;Live Demo&lt;/strong&gt; on your project page.&lt;/p&gt;

&lt;p&gt;This opens a sandbox with multiple pages to test your tour without touching your real website.&lt;/p&gt;

&lt;p&gt;Or load your actual app and the tour will appear automatically for first-time visitors.&lt;/p&gt;

&lt;p&gt;To replay during testing, run in browser console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TourKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resetAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Bonus — Context-aware tours
&lt;/h2&gt;

&lt;p&gt;Different pages can have different tours.&lt;/p&gt;

&lt;p&gt;In the step editor, set a &lt;strong&gt;Trigger URL&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1&lt;/strong&gt;: no URL → shows on / (homepage)&lt;br&gt;
&lt;strong&gt;Step 2&lt;/strong&gt;: /dashboard → shows on dashboard only&lt;br&gt;
&lt;strong&gt;Step 3&lt;/strong&gt;: /settings → shows on settings only&lt;br&gt;
&lt;strong&gt;Step 4&lt;/strong&gt;: /products/[id] → shows on any product page&lt;/p&gt;

&lt;p&gt;Each page gets its own focused tour. Users only see what's relevant to where they are.&lt;/p&gt;

&lt;p&gt;Dynamic URL segments are supported:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;/products/[id]&lt;/strong&gt;         → matches /products/123&lt;br&gt;
&lt;strong&gt;/blog/[category]/[slug]&lt;/strong&gt;→ matches /blog/tech/my-post&lt;br&gt;
/dashboard/*               → matches all dashboard pages&lt;/p&gt;


&lt;h2&gt;
  
  
  What the tour looks like
&lt;/h2&gt;

&lt;p&gt;On desktop:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Spotlight overlay highlights the element&lt;/li&gt;
&lt;li&gt;Tooltip appears next to it&lt;/li&gt;
&lt;li&gt;Smooth transitions between steps&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On mobile:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Element highlighted at top&lt;/li&gt;
&lt;li&gt;Tooltip slides up as a bottom sheet&lt;/li&gt;
&lt;li&gt;Large tap targets for buttons&lt;/li&gt;
&lt;/ul&gt;


&lt;h2&gt;
  
  
  The TourKit API
&lt;/h2&gt;

&lt;p&gt;After installation, these methods are available globally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Start tour for current page&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TourKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;start&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Start tour for specific page&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TourKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;startFor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/dashboard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Destroy active tour&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TourKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Reset seen flag for current page&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TourKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;reset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c1"&gt;// Reset all seen flags&lt;/span&gt;
&lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TourKit&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resetAll&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Analytics
&lt;/h2&gt;

&lt;p&gt;TourKit automatically tracks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tour started&lt;/li&gt;
&lt;li&gt;Each step viewed&lt;/li&gt;
&lt;li&gt;Tour completed&lt;/li&gt;
&lt;li&gt;Tour skipped&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;View analytics per project in your dashboard.&lt;br&gt;
See completion rates and step dropoff.&lt;/p&gt;




&lt;h2&gt;
  
  
  Pricing
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Free&lt;/strong&gt; — 1 project, 500 sessions/month&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Starter&lt;/strong&gt; — $9/mo, 3 projects, 2000 sessions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt; — $19/mo, unlimited + AI tour generator&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start free at tourkit-phi.vercel.app&lt;/p&gt;




&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;In 5 minutes, you can have a fully working onboarding tour on your React or Next.js app:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;✅ Create project → get script key&lt;/li&gt;
&lt;li&gt;✅ Add script tag to layout&lt;/li&gt;
&lt;li&gt;✅ Add TourKitProvider for route changes&lt;/li&gt;
&lt;li&gt;✅ Configure steps from the dashboard&lt;/li&gt;
&lt;li&gt;✅ Test on live demo page&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;No framework lock-in. No complex config. One script tag.&lt;/p&gt;




&lt;p&gt;If you try it, let me know how it goes.&lt;/p&gt;

&lt;p&gt;Happy to help with CSS selectors or any setup questions in the comments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Live Here - &lt;em&gt;&lt;a href="https://tourkit-phi.vercel.app" rel="noopener noreferrer"&gt;Tourkit&lt;/a&gt;&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>webdev</category>
      <category>react</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
