AI Integration
OpenAI API Integrations for Websites: A Practical Implementation Guide
An OpenAI API integration on a website is a server program that sends a bounded prompt, optionally with retrieved context, and returns text or JSON to your UI. It is not a script tag with a secret in it. If the key is in JavaScript, it is public. Anyone can copy it, run up a bill, and use your quota for content you did not approve. This guide is the implementation shape that keeps the key on the server and the feature narrow enough to be useful.
The only acceptable place for the secret
Store the API key in environment configuration on the server (or a secret manager), load it in PHP or another backend language, and call the API from there. The browser sends the user’s question to your URL. Your code checks a CSRF token or a logged-in session, applies rate limits, attaches server-side context, then calls OpenAI. The browser never sees the secret, and it should not see other customers’ retrieved chunks either.
Publishable identifiers are different from secrets. If a product has a publishable key, it is designed to be in the client. OpenAI secret keys are not. Do not proxy the entire OpenAI API to the internet “for flexibility.” Expose only the one operation you wrote: “answer from these docs,” “summarize this staff-provided text,” “extract these fields.” That reduction is also a secure web development habit: least privilege for every endpoint.
A request lifecycle you can explain on a whiteboard
- Client POSTs a small JSON payload: question, page locale, optional thread id.
- Your server authenticates the call (session, signed widget token, or both).
- You rate-limit by IP and by account. Cheap bots love chat endpoints.
- You retrieve allowed context (SQL, search index, or a fixed policy pack).
- You build a prompt with a system section you control and user content you treat as untrusted.
- You call the API with timeouts, max tokens, and a JSON schema if you need structure.
- You validate the output, log metadata (not necessarily full PII), and return a safe payload to the client.
Treat user content as hostile. Instruction-following models will try to obey “ignore the system prompt.” Your code should not grant extra tools because the user asked. If you use function calling, the functions are a hard allowlist implemented in your language, not a promise in the prompt.
Prompt design that stays maintainable
Keep the system prompt in version control. Put policy text in retrieval, not in a 4,000-word system message you cannot test. Ask for citations as URL list items your UI can render as links. For extraction jobs, ask for JSON and reject responses that do not match the schema — then retry once or fail closed. Temperature can be low for support and extraction; creative copy for a staff draft tool can be higher, but that tool should not be public.
Models, cost, and failure
Pick a model tier that matches the job. Classification and extraction often do not need the most expensive model. Cache embeddings and cache frequent Q&A pairs. Set billing alerts at the provider and a hard daily cap in your app if you can. On timeout or 429, return a controlled error; do not retry in an infinite client loop. Stream tokens for chat UIs so the connection is not a blank wait, and still enforce max length.
| Practice | Why |
|---|---|
| Key only on the server | Stops drive-by theft from “view source” |
| Separate keys per environment | A leaked staging key should not be production |
| Separate keys per product if possible | Easier rotation and clearer invoices |
| No key in git, screenshots, or chat | Assume anything pasted is public later |
| Rotate on staff change | Same rule as database passwords |
| Minimal user data in prompts | Reduces leak surface in logs and vendor retention |
Logging, privacy, and vendor settings
Decide what you store: the question, the answer, retrieved ids, latency, token counts. Full prompt dumps are convenient for debugging and uncomfortable for privacy. Redact emails and order ids in logs if you can still debug without them. Read the current OpenAI usage and training policies for the API product you buy; they change, and they differ by account type. If a contract requires that inputs not train a model, that is a procurement step, not a CSS class on the widget.
Do not send payment card numbers, passwords, or government ids to the model. If a user pastes them, strip or refuse. Your UI copy can say “do not include card details.”
Testing before the homepage
Keep a fixture file of questions and expected behaviours: must cite a given URL, must refuse medical advice, must not emit a competitor’s coupon. Run it when you change the prompt. Include multilingual abuse if you serve more than one language. Load-test the endpoint enough to know your PHP-FPM or Node workers will not melt when a campaign hits.
- Never commit
.envfiles. Use.env.examplewith empty placeholders. - Block the endpoint from search indexing if it is a debug UI.
- Use HTTPS everywhere; mixed content will leak tokens in some setups.
- Review CORS: an open
*with cookie auth is a gift to other sites.
Scriplit implements this pattern in PHP on client sites as part of AI integration services. If you want an integration on an existing stack, say which language the site already runs and whether the first endpoint can be staff-only, via the AI integration contact form. Do not paste live secret keys in that message.