<?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: JustOneCX</title>
    <description>The latest articles on DEV Community by JustOneCX (@justonecx).</description>
    <link>https://dev.to/justonecx</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%2F4228935%2Fc725861a-29e2-488f-a101-cebd1ac78cda.png</url>
      <title>DEV Community: JustOneCX</title>
      <link>https://dev.to/justonecx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/justonecx"/>
    <language>en</language>
    <item>
      <title>How to add a product tour to your web app with Claude Code or Cursor</title>
      <dc:creator>JustOneCX</dc:creator>
      <pubDate>Thu, 05 Nov 2026 16:03:32 +0000</pubDate>
      <link>https://dev.to/justonecx/how-to-add-a-product-tour-to-your-web-app-with-claude-code-or-cursor-19d0</link>
      <guid>https://dev.to/justonecx/how-to-add-a-product-tour-to-your-web-app-with-claude-code-or-cursor-19d0</guid>
      <description>&lt;p&gt;You can add a product tour to a web app by asking your AI coding assistant to build it. The assistant reads your code, adds stable anchors to the elements the tour points at, saves the tour as a draft and gives you a preview link. Nothing reaches your users until you publish. This guide shows each step with JustOneCX, the tool I am building (disclosure), and what to check before you press publish.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do you need first?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;A web app you can edit, and a coding assistant: Claude Code, Codex, Cursor or Gemini CLI.&lt;/li&gt;
&lt;li&gt;A JustOneCX workspace and its public key (&lt;strong&gt;Settings → Developers&lt;/strong&gt;, starts with &lt;code&gt;pk_&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Your site's origin added in &lt;strong&gt;Settings → Developers → Domains &amp;amp; CORS&lt;/strong&gt;. For local work add &lt;code&gt;http://localhost:3000&lt;/code&gt; or your dev port.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you prefer to do it by hand, the &lt;a href="https://docs.justonecx.com/quickstart" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt; covers that in about five minutes. The rest of this guide is the assistant route.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you connect your assistant?
&lt;/h2&gt;

&lt;p&gt;JustOneCX runs a remote MCP server. In Claude Code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add &lt;span class="nt"&gt;--transport&lt;/span&gt; http justonecx https://api.justonecx.com/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run &lt;code&gt;/mcp&lt;/code&gt;, pick &lt;code&gt;justonecx&lt;/code&gt; and sign in through your browser. You choose the workspace and how much the assistant may do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;See your content and setup:&lt;/strong&gt; reads only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Create and edit drafts:&lt;/strong&gt; the default. Nothing your users see changes until a person publishes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Make changes live:&lt;/strong&gt; can also publish. It is off unless you choose it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The assistant can never do more than your own role allows. Cursor, Codex and Gemini CLI use a short config entry instead. The &lt;a href="https://docs.justonecx.com/ai/mcp" rel="noopener noreferrer"&gt;MCP guide&lt;/a&gt; has each one. No token goes in any config file.&lt;/p&gt;

&lt;h2&gt;
  
  
  What do you ask for?
&lt;/h2&gt;

&lt;p&gt;Name one flow. For example: "Add a product tour for the export screen." A vague request such as "add a tour" makes the assistant study your product first and propose a ranked list of options. It then asks which one to build. It does not build all of them.&lt;/p&gt;

&lt;h2&gt;
  
  
  What does the assistant do?
&lt;/h2&gt;

&lt;p&gt;Here is the order it works in.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Finds the flow in your code.&lt;/strong&gt; It looks up the route and components, then picks the three to seven moments a new user must notice. Fewer steps are better.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adds anchors.&lt;/strong&gt; On each element a step points at, it adds a &lt;code&gt;data-jcx&lt;/code&gt; attribute such as &lt;code&gt;data-jcx="export-format-select"&lt;/code&gt;. This is a normal code change in your repo, so you review it like any other. It also checks your build config for anything that strips &lt;code&gt;data-*&lt;/code&gt; attributes in production.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Saves a draft.&lt;/strong&gt; It writes the tour with &lt;code&gt;save_content&lt;/code&gt;. A small tour looks like this:
&lt;/li&gt;
&lt;/ol&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;"key"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"export-flow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tour"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Export your data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"targeting"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"pages"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"include"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="nl"&gt;"operator"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"startsWith"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"value"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/settings/export"&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;span class="nl"&gt;"exclude"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&gt;}&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;span class="nl"&gt;"steps"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"welcome"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"modal"&lt;/span&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;"Export your data"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Two quick steps and your file is on its way."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"ctaLabel"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Show me"&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;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pick-format"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tooltip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&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-jcx=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;export-format-select&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]"&lt;/span&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;"Pick a format"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"CSV for spreadsheets, JSON for developers."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"arrowPosition"&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="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&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;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"run-export"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"tooltip"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"target"&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-jcx=&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;export-run-button&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;]"&lt;/span&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;"Start the export"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"body"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"We email you a link when it's ready."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"arrowPosition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"top"&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;span class="p"&gt;]&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;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;ol&gt;
&lt;li&gt;
&lt;strong&gt;Checks it.&lt;/strong&gt; &lt;code&gt;validate_tour&lt;/code&gt; checks the selectors, the page rule and the step flow. The assistant fixes any selector marked brittle and prefers &lt;code&gt;data-jcx&lt;/code&gt; anchors.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gives you a preview link.&lt;/strong&gt; The link plays the draft on your site for 24 hours.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;It also matches the look of your app when you ask for it, using your theme and design tokens, and picks which side of each element the tooltip sits on from where the element is on the screen. If it cannot tell, it asks you.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you review before it goes live?
&lt;/h2&gt;

&lt;p&gt;Check three things.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The code diff.&lt;/strong&gt; Only &lt;code&gt;data-jcx&lt;/code&gt; attributes should have changed. Anything else is worth a question.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The preview.&lt;/strong&gt; Open the link. Walk through every step. Read the copy: each step should have a short title and one sentence in your users' words.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Who sees it.&lt;/strong&gt; By default a tour with no targeting shows to everyone on every page. Set page and segment rules if that is not what you want. See &lt;a href="https://docs.justonecx.com/guides/targeting" rel="noopener noreferrer"&gt;targeting&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then publish. With the default access level the assistant cannot publish, so you click &lt;strong&gt;Publish&lt;/strong&gt; in the dashboard. If you gave it "Make changes live", it publishes only after you say yes.&lt;/p&gt;

&lt;h2&gt;
  
  
  What will the assistant not do?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;It never reads, returns or asks for your Secret key. You set &lt;code&gt;JUSTONECX_SECRET_KEY&lt;/code&gt; in your own server environment.&lt;/li&gt;
&lt;li&gt;It cannot empty the Trash, export survey responses as a file, or change members, roles, billing or keys. For those it points you to the dashboard page.&lt;/li&gt;
&lt;li&gt;Every change it makes shows in your audit log as made by the AI assistant.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What if the tour does not show?
&lt;/h2&gt;

&lt;p&gt;Open your site in a new window. If nothing starts, check the origin in &lt;strong&gt;Domains &amp;amp; CORS&lt;/strong&gt;, the page rule in the tour's targeting and whether the tour is published. The &lt;a href="https://docs.justonecx.com/troubleshooting" rel="noopener noreferrer"&gt;troubleshooting page&lt;/a&gt; lists the rest. If an element is not on the page yet, the SDK waits for it (5 seconds by default) and skips the step if it never appears. See &lt;a href="https://docs.justonecx.com/guides/tours" rel="noopener noreferrer"&gt;how steps are shown&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What next?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Add a "Show me how" button that starts the tour from your code with &lt;code&gt;startTour("export-flow")&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Add an announcement or a survey the same way. The assistant uses the same flow for both.&lt;/li&gt;
&lt;li&gt;Read the &lt;a href="https://docs.justonecx.com/guides/tours" rel="noopener noreferrer"&gt;tours guide&lt;/a&gt; for multi-page tours and checklists.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plans from $199/month, priced by monthly active users. Every plan has every feature. If you want to see it first, you can &lt;a href="https://calendly.com/hasan-py/any-meeting" rel="noopener noreferrer"&gt;book a demo&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>producttour</category>
      <category>onboarding</category>
      <category>ai</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
