Published May 13, 2026 · Neel Shah

Tribal Detox is one of the most established Kambo training schools in the world, but finding it on Google was like searching for hidden treasure. I rebuilt the site so search engines could finally see everything on it, added hundreds of indexable pages with crawlable content that could each earn their own spot in search and inside LLM answers, and gave the owner simple controls to keep it that way - all within budget. Halfway through the project, the site's average position in search had roughly halved. By the end, it was back on the first page for both of the keyword searches my client's business depends on.
Tribal Detox previously worked with my buddy Amish Menon, who had rebuilt their original site a few years before, using Create React App against a Sanity CMS. I had helped out on the UX side during that build. Afterward, Amish and I handled ad-hoc requests for Jason as they came in, small tickets mostly, enough to build a working relationship over a couple of years.
When Amish picked up a full-time role and stepped back from freelance, the maintenance relationship transferred to me. In late February, Jason emailed us both:
"Do you guys do SEO, back links, etc. I searched Kambo schools and Kambo trainings and Tribal Detox didn't even come up. Some of the schools that did come up, I've never even heard of. Is it possible to improve this?"
That email was sent with urgency, so I knew something had to change quickly. Tribal Detox's practitioner training school is the heart of Jason's business. In Jason's words, "we are the most popular school in the world," and he had the numbers to prove the problem was real: the school used to bring in 10 to 15 inquiries a month. By the time he wrote to us, it was down to one or two, if any at all. He was specific about where to aim the program: the schools and the trainings, not Kambo in the abstract. The searches that mattered were "kambo training" and "kambo schools."
Kambo is a traditional Amazonian medicine practice, and Tribal Detox covers all three sides of it: ceremonies, the training school, and an ecommerce store that supplies working practitioners. This puts the whole site within a sensitive category Google calls YMYL (your money or your life), where the bar for ranking in search results is higher than usual and the reward for clearing it is meaningful. So I started with an SEO audit. Though the Tribal Detox brand has real, verifiable authority, the site was ranking below schools with a fraction of its reputation, showing at the bottom of page one or the top of page two for "kambo training" and "kambo schools," varying by region. Something structural was holding it back.
The problem turned out to be largely based on how the site was built. The original version based on Create React App assembled each page inside the visitor's browser (client-side rendering), a step that finishes a moment too late: search engines mostly judge a site by the raw page they receive first, before that step runs. So, when Google looked at Tribal Detox, it saw something close to a blank page. All the real content was there, managed in a proper content system, but it sat behind a curtain that search engines do not reliably pull back. The site was getting by on its reputation alone and leaving the rest of its potential on the table!
I provided Jason three options: a quick five hour pass that would move the SEO needle initially but eventually fade, a ground-up rebuild of around twenty-five hours that would have a lasting impact, or open-ended iterative work that he could stop at any time. He decided to go with the full rebuild, knowing that the foundational work would benefit his business in the long term. We began a two-month Statement of Work in early March 2026.
The Statement of Work had nine line items:
You can find countless ways to make SEO changes online, but in this case, none of those tactics would really pay off without addressing the core issue: making the pages more readable for Google and other search engine crawlers. The framework and other code migrations needed to happen first in order to unlock the full benefits of the other SEO improvements like structured metadata or performance. And all of these changes would need to be made without affecting the functionality of the site.
I first migrated the underlying frameworks, libraries and site content over to more modern, SEO-friendly structures.
Most websites are built one of two ways. Client-side rendering (CSR), the pattern Create React App uses by default, ships a near-empty HTML shell and assembles the page in the visitor's browser using JavaScript. CSR is a popular choice because it offers app-like navigation after the first load and can be hosted cheaply as static files. Server-side rendering (SSR), the pattern Next.js is designed for, has the server deliver a fully populated HTML page on the first request. Nowadays, search engines and LLMs strongly prefer quick crawl results, so they read the raw HTML they receive first and may never run the JavaScript at all. A CSR site can be invisible to them while looking perfect to a human visitor. SSR closes that gap.
I migrated the site from Create React App to Next.js 16 on the App Router. With that change, crawlers receive the finished page on first load instead of an empty container, and the whole standard SEO toolbox (sitemap, robots, canonical URLs, per-page metadata) becomes available out of the box.
The framework swap was only the beginning. The rest of the migration focused on bringing the existing components into the new model. I inspected and classified more than sixty components, and addressed four specific challenges along the way:
react-helmet-async → Metadata API. The old site set page metadata imperatively in JavaScript after the page loaded. Next.js wants metadata declared statically in each route module, or generated via generateMetadata, so it lands in the HTML on the first request. Every page's <head> choreography had to be re-expressed in this model.'use client' or left to render on the server. Getting the boundary wrong silently breaks rendering.react-router-dom → file-based routing. Every route had to be restructured from programmatic configs into the App Router's directory layout, including nested layouts and dynamic segments.react-query → server components with fetch + revalidate. Client-side data fetching patterns had to be replaced with server-side data fetching directly inside server components, each with the right revalidate cadence for how often that content actually changes.Once I completed this part of the migration the site had search-engine-friendly HTML on every existing URL!
Three of the most important content types were trapped on single pages: the training program, the practitioner directory, and the product catalog. The training program in particular previously lived entirely on one page that described it in general terms. All globally known schools were represented to search engines by a single URL. This was an artifact of the client-side rendering since each school was displayed in more detail after a user interaction.
The fix was the same across all three. Every training location, every practitioner, and every product became its own URL with a slug derived from the content. One page became hundreds. School pages now surface their instructor, venue, and upcoming cohorts, and each one targets searches that name a city while becoming eligible for the Google Course carousel. The legacy product route stayed alive behind a permanent redirect so any backlinks under the old path pass equity to the new one.
a dedicated school location pageIt might seem counterintuitive to add hundreds of pages about practitioners and products when Jason's priority was the schools. The reason is topical authority. Search engines reward sites that demonstrate depth on a subject, and a site that covers every angle of Kambo (the practice, the practitioners, the supplies, the training) reads as more authoritative on the topic as a whole. Each new page also catches its own long-tail searches. Someone looking for a Kambo practitioner in their city, or shopping for a specific supply, lands on Tribal Detox first and can discover the training program from there.
For search engines to find all those new pages, I implemented a dynamic sitemap that reads from Sanity. Every new entry in the CMS is indexed without having to redeploy the site. A new school in Creede, Colorado taught by Jason might end up at /schools/creede-colorado-jason, or any custom slug configured by a site admin in Sanity.
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const data = await sanityClient.fetch(sitemapQuery);
const productRoutes = (data.products || []).map((product) => ({
url: product.slug
? `${BASE_URL}/shop/${product.slug}`
: `${BASE_URL}/e-commerce/product/${product._id}`,
lastModified: new Date(product._updatedAt),
changeFrequency: 'weekly' as const,
priority: 0.6,
}));
const schoolRoutes = (data.courseLocations || [])
.filter((loc) => loc.slug)
.map((loc) => ({
url: `${BASE_URL}/schools/${loc.slug}`,
lastModified: new Date(loc._updatedAt),
changeFrequency: 'weekly' as const,
priority: 0.7,
}));
const practitionerRoutes = (data.practitioners || [])
.filter((p) => p.slug)
.map((p) => ({
url: `${BASE_URL}/practitioners/${p.slug}`,
lastModified: new Date(p._updatedAt),
changeFrequency: 'monthly' as const,
priority: 0.6,
}));
return [...staticRoutes, ...productRoutes, ...schoolRoutes, ...practitionerRoutes];
}With the migrations completed, the site was ready for me to add in tasty structured metadata for the crawlers to consume! This effort helps the crawlers identify exactly what type of content is on each page and how it should categorize things semantically.
JSON-LD is a small block of structured JSON embedded in each page's HTML that tells search engines exactly what the page is (a course, an article, a product, a person) and the relationships between those things. Google, Bing, and the AI crawlers all read it. A well-marked-up page is dramatically easier for them to interpret correctly, and eligible for richer result formats like the carousels, the highlighted snippets, and the in-result ratings.
I rolled structured data across the site:
@id so it can be referenced from anywhere/what-is-kambo, with named authorshipThe Course schema on the school location pages is the most ambitious of the lot. The page describes a course; the course has instances (the scheduled cohorts); each cohort has dates, pricing, and availability. When seats remain, the cohort reads as available. When they run out, it flips to sold out automatically, so the markup Google sees never drifts from reality.
{
'@context': 'https://schema.org',
'@type': 'Course',
name: `Kambo Practitioner Training - ${locationName}`,
educationalCredentialAwarded: 'Kambo Practitioner Certification',
provider: { '@id': 'https://www.tribaldetox.com/#organization' },
...(school.courseDates?.length > 0 && {
hasCourseInstance: school.courseDates.map((event) => ({
'@type': 'CourseInstance',
courseMode: 'onsite',
location: { '@type': 'Place', name: locationName, /* address */ },
...(event.eventStartDate && { startDate: event.eventStartDate }),
...(event.eventEndDate && { endDate: event.eventEndDate }),
...(school.depositAmount && {
offers: {
'@type': 'Offer',
price: String(school.depositAmount),
priceCurrency: 'USD',
availability:
event.seatsRemaining === 0
? 'https://schema.org/SoldOut'
: 'https://schema.org/InStock',
},
}),
...(school.courseInstructor && {
instructor: { '@type': 'Person', name: school.courseInstructor },
}),
})),
}),
}For a YMYL topic, structured data alone is not enough. Search engines also weigh whether the content has an attributable expert behind it, and whether claims are sourced. Even when the content isn't directly about the training schools, search engines evaluate trust at the site level: a credible, well-sourced article about Kambo raises the authority of every page on the domain, including the school pages Jason wanted to rank.
The biggest change here was on /what-is-kambo, the educational article that explains what Kambo is, what it does, and how it is used. I marked the article with Article schema, with Jason Fellows as the named author, and added external citations for the medical claims that warrant them. The pharmacology references include a PubMed Central article on Phyllomedusa bicolor, the PubMed catalog of published research on the species, and the research profile of V. Erspamer, the pharmacologist who first characterized the active peptides. These citations are the kind of authoritative evidence that gives search engines a trust and safety signal on a sensitive topic.
To carry the safety signal across every page rather than just the article, I added a site-wide contraindications disclaimer in the footer, fetched from Sanity so Jason can update the medical guidance without waiting on a developer.
the site-wide medical disclaimerWith the site providing maximum surface area, content depth and authority signals, it was now the perfect time for me to optimize the implementation. Leveraging the systematic changes, I was able to provide maintainable code and content in various ways.
Sanity is a headless content management system, which is to say a tool the site owner uses to edit content without touching code. Amish had already set Sanity up for the original site, so I built on his existing schema rather than starting from scratch. A migration only I can maintain has a shelf life, so I added an SEO section to every significant content type. Page title, meta description, social preview image, and an index flag now live alongside the body content. The metadata is content now, not configuration. If Jason adds more content and needs to add metadata or tweak any existing SEO changes, he can do so himself for free!
the new SEO fields in SanitySearch engines re-crawl on their own schedule, and that schedule can be days. When a school adds a cohort or fixes a price, the version of the page Google has cached may not reflect the change for a while.
Next.js does its best to notify crawlers of changes, but it won't know about changes in the Sanity content. I implemented a webhook that closes the loop. Sanity publishes, the route validates the signature, deduplicates against retry deliveries, dispatches a targeted cache invalidation based on what kind of document changed, and fires off an IndexNow ping so Bing and Yandex re-crawl within minutes instead of days.
function revalidateForType(type, id, slug) {
const indexNowUrls = [];
switch (type) {
case 'landingPage':
revalidatePath('/');
indexNowUrls.push(`${SITE_URL}/`);
break;
case 'practitioner':
revalidatePath('/practitioners');
indexNowUrls.push(`${SITE_URL}/practitioners`);
if (slug) {
revalidatePath(`/practitioners/${slug}`);
indexNowUrls.push(`${SITE_URL}/practitioners/${slug}`);
}
break;
case 'ecommerceProducts':
revalidatePath('/e-commerce/products');
if (slug) {
revalidatePath(`/shop/${slug}`);
indexNowUrls.push(`${SITE_URL}/shop/${slug}`);
}
break;
// ... courseLocation, trainingCourse, imageGallery, storeSettings, default
}
return indexNowUrls;
}
export async function POST(request) {
const body = await request.text();
if (!(await isValidSignature(body, signature, secret))) return /* 401 */;
const idempotencyKey = request.headers.get('idempotency-key');
if (idempotencyKey && processedKeys.has(idempotencyKey)) {
return NextResponse.json({ revalidated: false, reason: 'duplicate delivery' });
}
const payload = JSON.parse(body);
const indexNowUrls = revalidateForType(payload._type, payload._id, payload.slug?.current);
if (indexNowUrls.length > 0) {
submitToIndexNow(indexNowUrls).catch((err) => console.warn('IndexNow ping failed:', err));
}
return NextResponse.json({ revalidated: true, type: payload._type });
}Note: The idempotency window matters more than it looks. Sanity retries webhook deliveries on a backoff, and without deduplication the same publish triggers two or three cache invalidations and IndexNow pings. Since Bing rate-limits IndexNow per key per hour, those noisy pings could defeat the purpose of the webhook if not caught.
Hero images on the original site were nearly two megabytes apiece. The site's image component did not handle responsive sizing, and the editorial workflow uploaded raw PNGs to Sanity without optimization. I made three changes:
The last piece addresses an audience that is not Google. The crawlers behind ChatGPT, Claude, Perplexity, Google AI Overviews, and Apple Intelligence operate independently of traditional search. Some respect explicit allow rules in robots.txt. Some look for an llms.txt index.
I added both to the site to cover all bases: a robots.txt with explicit allow rules for the nine AI crawler user-agents I cared about, and an llms.txt index that points the AI crawlers at a dynamically generated llms-full.txt they can read in one shot. Treating AI crawlers as a real audience is the difference between being cited and being skipped.
Here's a few of the smaller fixes that I was able to fit into the budget, polishing the SEO solution to maximize the long term benefits:
When I started, Tribal Detox sat at the bottom of page one or the top of page two for its most important searches, an average position around ten. Three weeks after the first changes went live, Google Search Console data showed the average position had climbed to 5.3. By the start of May, the site was ranking in the top ten for both "kambo training" and "kambo schools," and a clean search with no personalization put it back on the first page.
That is early data, and it will move as search engines digest the rest of the changes. But the direction is clear, and it is exactly what you would expect when a site with a strong reputation finally becomes easy to find.
search console: the indexed page count growing as the new slug routes get discovered
search console performance: average position climbing toward the first page
chatgpt surfacing tribal detox when asked about kamboIn plain terms, here is what changed for the business:
Beyond rankings, I am also watching how many pages Google has indexed, the site's loading-speed scores, and whether AI tools start citing Tribal Detox when people ask about Kambo. Check back here for updates as more data accumulates.
Note: Search ranking is a system nobody fully controls, and this engagement is recent, so I will show only what I can stand behind.
A site is never finished! The writeup I gave Jason at the end of this project included some impactful steps he could take to enhance the SEO of his site on his own too:
None of that requires another migration. That is the point of front-loading the foundation: the expensive work is done, and everything from here is lighter.
Three things stick with me about this project.
How a site is built is itself an SEO decision. For a site that shows search engines nothing on the first look, the choice of underlying technology is the gating choice for everything that follows. People sometimes treat the platform decision as separate from SEO. It is not. The schema work, the metadata work, the freshness pipeline, none of it would have been possible on the original stack without workarounds that search engines may not have respected.
For sensitive topics, content authority is the work, not a side quest. A site that touches health, money, or safety is held to a higher bar by search engines, and rankings on those topics are a trust assessment more than a checklist. Authority is built deliberately: name an attributed expert as the author, cite the medical and scientific claims to credible sources, surface safety guidance plainly, and let the depth of coverage across the whole topic do the rest. The article on Kambo got Jason's byline, PubMed and ResearchGate citations, and a site-wide contraindications disclaimer in the footer. None of those changes are flashy, but together they raise the credibility of every page on the domain.
SEO is never done. Even after a focused two-month engagement, the long tail of smaller fixes is evidence of how many small wins remain on the table at any given moment. Modern SEO touches structured data, page speed, AI crawler access, content depth, internal linking, freshness signals, and a dozen other surfaces, and each of those evolves as search engines and AI tools do. There is always more to optimize, more to refine, and more ways the site can compound the work that has already been done.
Jason's situation is not unique and happens all the time: a business with something real to offer, and a website quietly keeping it a secret. A nonprofit whose programs nobody can find. A shop whose products never surface. A firm whose expertise is buried where search engines never look. If that sounds like your site, the encouraging part is that it is fixable, and the fix is not mysterious! It usually starts with a careful look and an honest conversation and I would be glad to have that conversation with you.
Neel has been amazing to work with. He is always quick to respond and fast to act on requests. He has done an exceptional job with our website and SEO.
Before working with him, we were barely showing up in Google searches. Within just a few days, he had us ranking on the first page and climbing toward the top. What impressed me most is that he doesn't just make a few surface-level adjustments. He really dives deep into all the factors that make a website more visible and easier to find online.
I highly recommend Neel for anyone needing website development or SEO work. You will not be disappointed.
