You’re getting this because the Domains page expects JSON, but the server responded with HTML (most commonly a 404/500 error page or an auth error from GoDaddy). Hence the client tries response.json() and explodes on the leading < (<!DOCTYPE ...).

Let’s fix this in two places:

1) Client-side: make the mutation robust to non-JSON

Replace your mutationFn in DomainsPage with this safer parser:

// helper: parse JSON if possible, otherwise throw a readable error
async function parseJsonSafe(res: Response) {
  const raw = await res.text();
  const ct = res.headers.get('content-type') || '';
  const isJson = ct.includes('application/json');

  if (!res.ok) {
    // If server returned JSON error, try to include it
    if (isJson) {
      try {
        const err = JSON.parse(raw);
        throw new Error(err.message || err.error || `HTTP ${res.status}`);
      } catch {
        throw new Error(`HTTP ${res.status}`);
      }
    }
    // Otherwise it's likely HTML
    const snippet = raw.slice(0, 160).replace(/\s+/g, ' ');
    throw new Error(`HTTP ${res.status}: Non-JSON response (${snippet})`);
  }

  // OK responses:
  if (isJson) return JSON.parse(raw);
  throw new Error('Expected JSON but received non-JSON response from server.');
}

const searchMutation = useMutation({
  mutationFn: async (domain: string) => {
    const res = await apiRequest("POST", "/api/domains/search", { domain });
    return parseJsonSafe(res);  // <-- use robust parser
  },
  onSuccess: (data: DomainSearchResult[]) => {
    setSearchResults(data);
  },
  onError: (error: Error) => {
    toast({
      variant: "destructive",
      title: "Search Failed",
      description: error.message || "Failed to search domains. Please try again.",
    });
  },
});


Now, even if the API sends HTML (error page), the UI will show a clean message instead of crashing on response.json().

2) Server-side: ensure /api/domains/search always returns JSON

Most likely causes of HTML coming back:

The route /api/domains/search is missing/typo’d → server returns your HTML app shell (Next/SPA) or 404 page.

The server calls GoDaddy without auth or to the wrong URL → GoDaddy returns an HTML error page.

An unhandled exception → default HTML error page.

Here’s a minimal Express route that calls GoDaddy’s availability API and always returns JSON in the shape your UI expects:

// server/routes/domains.ts
import express from 'express';
import fetch from 'node-fetch';

const router = express.Router();

type DomainSearchResult = {
  domain: string;
  available: boolean;
  price: number;     // micros
  currency: string;  // e.g., USD
  period: number;    // years
  definitive: boolean;
};

const GD_API = process.env.GODADDY_API || 'https://api.godaddy.com';
const GD_KEY = process.env.GODADDY_KEY!;
const GD_SECRET = process.env.GODADDY_SECRET!;

// Helper to respond with JSON error consistently
function jsonError(res: express.Response, status: number, message: string) {
  return res.status(status).json({ error: message });
}

router.post('/api/domains/search', async (req, res) => {
  try {
    const { domain } = req.body as { domain?: string };
    if (!domain) return jsonError(res, 400, 'Missing domain');

    // GoDaddy availability (FAST check); returns price in micros for available domains
    const url = new URL(`${GD_API}/v1/domains/available`);
    url.searchParams.set('checkType', 'FAST');
    url.searchParams.set('domain', domain);

    const gdRes = await fetch(url.toString(), {
      headers: {
        Accept: 'application/json',
        Authorization: `sso-key ${GD_KEY}:${GD_SECRET}`,
      },
    });

    const raw = await gdRes.text();
    if (!gdRes.ok) {
      // Try to pass through GoDaddy’s JSON error, otherwise generic
      try {
        const err = JSON.parse(raw);
        return jsonError(res, gdRes.status, err.message || err.code || 'GoDaddy API error');
      } catch {
        return jsonError(res, gdRes.status, `GoDaddy API error ${gdRes.status}`);
      }
    }

    let parsed: any;
    try {
      parsed = JSON.parse(raw);
    } catch {
      return jsonError(res, 502, 'Invalid JSON from GoDaddy');
    }

    // Map to your DomainSearchResult[]
    // Single domain request → wrap as one-item array
    const out: DomainSearchResult[] = [
      {
        domain,
        available: !!parsed.available,
        price: typeof parsed.price === 'number' ? parsed.price : 0, // micros
        currency: parsed.currency || 'USD',
        period: parsed.period || 1,
        definitive: parsed.definitive !== false, // default true if absent
      },
    ];

    return res.json(out);
  } catch (e: any) {
    console.error('domains/search error', e);
    return jsonError(res, 500, e?.message || 'Internal error');
  }
});

export default router;


Wire it up in your server:

// server/index.ts
import express from 'express';
import domainsRouter from './routes/domains';

const app = express();
app.use(express.json());
app.use(domainsRouter);

// ...your other routes & static serving...


.env

GODADDY_API=https://api.godaddy.com
GODADDY_KEY=prod_xxxxx
GODADDY_SECRET=yyyyyyyyyyyy


If you’re using GoDaddy’s OTE sandbox, set GODADDY_API=https://api.ote-godaddy.com and use OTE creds.

Quick sanity checks

Is the route reachable?
Open DevTools → Network → see that POST /api/domains/search returns 200 + JSON (not HTML).

Wrong path?
If your dev server proxies API to another port, ensure the proxy forwards /api/domains/* to your Node server. Otherwise your SPA may serve HTML for that path.

CORS?
If you’re calling from a different origin, enable CORS or use your dev proxy. HTML CORS errors often masquerade as HTML responses.