Keystonejs Troubleshooting: Common Issues and Fixes | OpsBlu Docs

Keystonejs Troubleshooting: Common Issues and Fixes

Debug analytics issues on KeystoneJS — GraphQL API integration, Admin UI preview conflicts, custom field rendering, and Next.js frontend coupling problems.

KeystoneJS is a Node.js headless CMS and application framework that provides a GraphQL API and an auto-generated Admin UI. Since KeystoneJS is a backend framework (not a full CMS with a frontend), analytics issues live in your custom frontend code that consumes the KeystoneJS GraphQL API. Most KeystoneJS sites pair it with Next.js or a similar React framework.

KeystoneJS-Specific Debugging Approach

KeystoneJS serves as both your CMS and your API layer. Debugging analytics means checking the GraphQL API output and your frontend's rendering pipeline.

Verify GraphQL API Data

# Check if your KeystoneJS API returns analytics config
curl -s -X POST "http://localhost:3000/api/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ siteSettings { trackingId gtmContainerId } }"}' \
  | python3 -m json.tool
// In browser console on your frontend
console.log('Analytics scripts:', document.querySelectorAll('script[src*="gtag"], script[src*="gtm"]').length);

// Check if KeystoneJS data made it to the client
console.log('SSR data:', window.__NEXT_DATA__?.props?.pageProps || 'not found');

Check KeystoneJS Server Logs

# KeystoneJS logs to stdout by default
# If running with Node:
pm2 logs keystone
# Or check the terminal where KeystoneJS is running

# Look for GraphQL query errors
grep -i "graphql\|error\|query" keystone.log

Most Common KeystoneJS Analytics Issues

1. GraphQL Query Not Fetching Settings

Symptoms: Frontend renders pages correctly but analytics code is missing. The GraphQL query for site settings returns null.

Root cause: The KeystoneJS list (model) for site settings either does not exist, has no published items, or the frontend query does not match the schema.

Diagnosis:

# Introspect the GraphQL schema
curl -s -X POST "http://localhost:3000/api/graphql" \
  -H "Content-Type: application/json" \
  -d '{"query":"{ __schema { types { name } } }"}' \
  | python3 -m json.tool | grep -i "setting"

Fix: Ensure your KeystoneJS schema includes a settings model:

// In keystone.ts (Keystone 6)
import { list } from '@keystone-6/core';
import { text } from '@keystone-6/core/fields';

export const lists = {
  SiteSettings: list({
    isSingleton: true, // Keystone 6 singleton pattern
    fields: {
      trackingId: text({ label: 'GA Tracking ID' }),
      gtmContainerId: text({ label: 'GTM Container ID' }),
      customHeadScript: text({ ui: { displayMode: 'textarea' } }),
    },
  }),
  // ... other lists
};

2. Access Control Blocking API Reads

Symptoms: GraphQL query returns null or access denied errors. Analytics config exists in the Admin UI but the frontend cannot read it.

Root cause: KeystoneJS access control rules may restrict reading the site settings list. If your frontend queries without authentication, access.operation.query may deny the request.

Fix: Allow public read access for site settings:

SiteSettings: list({
  access: {
    operation: {
      query: () => true,  // Allow unauthenticated reads
      create: ({ session }) => !!session, // Restrict writes to admin
      update: ({ session }) => !!session,
      delete: ({ session }) => !!session,
    },
  },
  fields: { /* ... */ },
}),

3. Admin UI Previews Inflating Analytics

Symptoms: Pageviews spike during content editing. KeystoneJS Admin UI URL patterns appear in GA.

Root cause: If your frontend and KeystoneJS run on the same origin, Admin UI interactions may trigger analytics on admin pages.

Fix:

// Suppress analytics on KeystoneJS admin routes
const isAdminUI = window.location.pathname.startsWith('/admin') ||
  window.location.pathname.startsWith('/api/graphql');

if (isAdminUI) {
  window['ga-disable-G-XXXXXXX'] = true;
}

4. SSR Data Fetching Failing Silently

Symptoms: Analytics works in development but not in production. No error messages visible.

Root cause: In production, the Next.js frontend may use a different URL to reach the KeystoneJS API. If the internal API URL is misconfigured, getServerSideProps or getStaticProps silently returns empty data.

Diagnosis:

# Check if your frontend can reach KeystoneJS from the server side
curl -s "http://keystone-internal:3000/api/graphql" \
  -X POST -H "Content-Type: application/json" \
  -d '{"query":"{ siteSettings { trackingId } }"}'

Fix: Ensure environment variables for the API URL are correctly set in production:

# .env.production
NEXT_PUBLIC_KEYSTONE_URL=https://api.your-site.com
KEYSTONE_INTERNAL_URL=http://keystone:3000  # For SSR fetches

5. Hot Module Replacement Re-executing Analytics in Dev

Symptoms: During development, analytics fires multiple times on each code change. Pageview counts are inflated in dev.

Root cause: Next.js HMR re-renders the layout component on each file save, re-executing analytics initialization code.

Fix: Guard against re-initialization:

// In your analytics initialization
if (typeof window !== 'undefined' && !window.__analyticsInitialized) {
  window.__analyticsInitialized = true;
  // Load and configure analytics
  gtag('config', 'G-XXXXXXX');
}

Environment Considerations

  • KeystoneJS 5 vs 6: Keystone 6 is a complete rewrite with different GraphQL schema generation, access control, and configuration. Ensure your debugging matches your version
  • Combined vs. separate deployment: Some sites run KeystoneJS and Next.js in the same process, others deploy them separately. Network connectivity between services matters for SSR
  • Database dependency: KeystoneJS requires PostgreSQL or SQLite. Database connectivity issues can cause empty API responses including missing analytics config
  • No built-in CDN: KeystoneJS does not include caching by default. Add caching at the reverse proxy level if API latency affects page rendering

Performance Issues

Tracking Issues

  • Events Not Firing - Debug GraphQL access control, API connectivity, and SSR data fetching