This guide covers the migration from the legacy dotAI field-based configuration to the new unified providerConfig JSON format. This fundamentally changes the configuration process, but enables a variety of possible providers, and more overall freedom in configuration.
No automatic migration is performed — existing configuration must be manually re-entered. This is important, as there are steps on both sides of the upgrade process.
What Has Changed
Previously, dotAI was configured through individual fields in the Apps UI (Settings > Apps > dotAI), each representing a distinct secret. The new format consolidates all configuration into a single JSON field called providerConfig.
To summarize the changes:
Changed Aspect | Before | After |
|---|---|---|
Apps Configuration UI | Individual form fields per setting | Single JSON textarea |
API key scope | One shared key for all operations | Declared per section (chat, embeddings, image) |
Custom behavior | Via "Additional Parameters" keys | Via settings block in the JSON |
API response (GET /config) | Individual flat fields | { "providerConfig": "...", "configHost": "..." } |
Important: Old secrets are not migrated and will not be read. After upgrading, the app will report as disabled until the new providerConfig is saved.
Migration Steps
1. Locate your existing values (pre-upgrade)
Before you upgrade, go to Settings > Apps > dotAI > SYSTEM_HOST and note down the current values for each field listed in the mapping tables in the Complete Field Mapping Reference section below.
2. Build your new providerConfig JSON
Use the template below as a starting point, replacing placeholder values with your own. Ensure your compiled config validates as well-formed JSON.
3. Save the new configuration
After the upgrade, return to Settings > Apps > dotAI > SYSTEM_HOST. You should now see the new Provider Config (JSON) field. (Note: If you do not see the new field, you may need to clear your browser cache.)
Paste the JSON configuration into the new field. Any data still stored in the old config will be ignored from this point forward.
Configuration Examples
Minimal (standard OpenAI, default behavior)
Sufficient for most deployments. Omit any section you don't use.
{
"chat": {
"provider": "openai",
"apiKey": "sk-...",
"model": "gpt-4o",
"maxTokens": 16384,
"maxRetries": 3
},
"embeddings": {
"provider": "openai",
"apiKey": "sk-...",
"model": "text-embedding-ada-002"
},
"image": {
"provider": "openai",
"apiKey": "sk-...",
"model": "dall-e-3"
}
}
With Custom Settings
Use the settings block only for values that differ from the defaults.
{
"chat": {
"provider": "openai",
"apiKey": "sk-...",
"model": "gpt-4o",
"maxTokens": 16384,
"temperature": 0.7,
"maxRetries": 3
},
"embeddings": {
"provider": "openai",
"apiKey": "sk-...",
"model": "text-embedding-ada-002"
},
"image": {
"provider": "openai",
"apiKey": "sk-...",
"model": "dall-e-3"
},
"settings": {
"rolePrompt": "You are a helpful assistant for Acme Corp.",
"textPrompt": "Be concise and professional.",
"imagePrompt": "Use a clean, corporate visual style.",
"imageSize": "1792x1024",
"listenerIndexer": {
"default": "blog,news,webPageContent"
},
"embeddingsSplitAtTokens": 256,
"embeddingsSearchThreshold": 0.3,
"debugLogging": false
}
}
With Model Fallback
If your primary model is unavailable, dotAI will automatically try the next one.
{
"chat": {
"provider": "openai",
"apiKey": "sk-...",
"model": "gpt-4o,gpt-4o-mini",
"maxTokens": 16384
}
}
With Custom Endpoint (self-hosted / proxy)
{
"chat": {
"provider": "openai",
"apiKey": "sk-...",
"model": "gpt-4o",
"endpoint": "https://your-proxy.example.com/v1/chat/completions"
}
}
Per-Site Configuration
Each site can override the SYSTEM_HOST configuration independently. Sites without their own configuration automatically inherit from SYSTEM_HOST.
To configure a specific site, go to Settings > Apps > dotAI, select the target site from the site picker, and save a separate providerConfig JSON.
To verify which host's config is being applied, check the configHost field in the GET response:
GET /api/v1/ai/completions/config?siteId=your-site-id
{
"providerConfig": "{ ... }",
"configHost": "SYSTEM_HOST"
}
If configHost returns the target site's hostname, the per-site config is active.
Verifying the Migration
After saving the new configuration:
1. Check the config endpoint
GET /api/v1/ai/completions/config
Expected: 200 with providerConfig containing your JSON (credentials masked as *****).
2. Test text generation
GET /api/v1/ai/text/generate?prompt=Hello
Expected: 200 with choices[0].message.content populated.
3. Test embeddings
GET /api/v1/ai/embeddings/test
Expected: 200 with type: "embeddings".
4. Test image generation
GET /api/v1/ai/image/test
Expected: HTTP 200 response with type: "image".
If any of these return an error indicating the app is disabled, verify that the JSON was saved correctly and includes at least one valid provider section with provider, apiKey, and model.
Considerations
Credentials re-entry required. As mentioned previously, there is no automatic migration. All API keys must be explicitly included in the new JSON. Once saved, credentials are masked in the UI and subsequent API responses — the only moment to verify them is immediately after saving.
Re-save with masked credentials is safe. If you retrieve the config via GET and PUT it back with ***** in place of credentials, the system will preserve the original values.
listenerIndexer format. In the old configuration this was stored as a plain string. In the new format it is a JSON object within settings:
"listenerIndexer": { "default": "blog,news,webPageContent" }
Temperature consolidation. The old com.dotcms.ai.completion.default.temperature additional parameter is now settings.temperature. This single value applies to all chat completions. If you also set chat.temperature, the provider-level value takes effect for LangChain4J model initialization, while settings.temperature is used downstream in the completions API. For consistent behavior, set temperature in settings only.
Embeddings must be rebuilt after changing the embeddings model. If you switch from one embeddings model to another (e.g., text-embedding-ada-002 to text-embedding-3-small), existing vectors are incompatible. Delete and recreate all indexes after the model change.
Default values are unchanged. If you were relying on the system defaults and not explicitly setting a value, behavior will be identical without including that key in the new JSON.
Complete Field Mapping Reference
The following tables are a comprehensive reference mapping old fields to new properties.
Core Model Fields
Old Field (App Secret) | New Location in providerConfig |
|---|---|
apiKey | chat.apiKey, embeddings.apiKey, image.apiKey |
model | chat.model |
imageModel | image.model |
embeddingsModel | embeddings.model |
apiUrl | chat.endpoint (omit for standard OpenAI) |
apiImageUrl | image.endpoint (omit for standard OpenAI) |
apiEmbeddingsUrl | embeddings.endpoint (omit for standard OpenAI) |
Prompt & Behavior Fields
Old Field (App Secret) | New Location in providerConfig | Default |
|---|---|---|
rolePrompt | settings.rolePrompt | "You are dotCMSbot..." |
textPrompt | settings.textPrompt | "Use Descriptive writing style." |
imagePrompt | settings.imagePrompt | "Use 16:9 aspect ratio." |
imageSize | settings.imageSize | "1024x1024" |
listenerIndexer | settings.listenerIndexer | {} |
Advanced / Additional Parameters
Old Additional Parameter | New Location in settings | Default |
|---|---|---|
com.dotcms.ai.completion.default.temperature | temperature | 1 |
com.dotcms.ai.completion.role.prompt | completionRolePrompt | You are a helpful assistant with a descriptive writing style. |
com.dotcms.ai.completion.text.prompt | completionTextPrompt | Answer this question\n\"$!{prompt}?\"\n\nby using only the information in the following text:\n\"\"\"\n$!{supportingContent} \n\"\"\"\n |
com.dotcms.ai.embeddings.split.at.tokens | embeddingsSplitAtTokens | 512 |
com.dotcms.ai.embeddings.minimum.text.length | embeddingsMinimumTextLength | 64 |
com.dotcms.ai.embeddings.minimum.file.size | embeddingsMinimumFileSize | 1024 |
com.dotcms.ai.embeddings.build.for.file.extensions | embeddingsFileExtensions | pdf,doc,docx,txt,html |
com.dotcms.ai.embeddings.search.default.threshold | embeddingsSearchThreshold | .25 |
com.dotcms.ai.embeddings.threads | embeddingsThreads | 3 |
com.dotcms.ai.embeddings.threads.max | embeddingsThreadsMax | 6 |
com.dotcms.ai.embeddings.threads.queue | embeddingsThreadsQueue | 10000 |
com.dotcms.ai.embeddings.cache.ttl.seconds | embeddingsCacheTtlSeconds | 600 |
com.dotcms.ai.embeddings.cache.size | embeddingsCacheSize | 1000 |
com.dotcms.ai.embeddings.delete.old.on.update | embeddingsDeleteOldOnUpdate | true |
com.dotcms.ai.debug.logging | debugLogging | false |
Fields not listed here have no equivalent and are no longer supported. Settings not included in the JSON fall back to their default values shown above.
Frequently Asked Questions
Will my existing dotAI configuration be migrated automatically?
No. Old field-based secrets are not read after the upgrade, and no automatic conversion is performed. You must manually re-enter your configuration as a single providerConfig JSON. This is why Step 1 (noting down your existing values before upgrading) is critical — once you upgrade, the old field values are no longer accessible through the UI.
Why does dotAI show as disabled immediately after the upgrade?
Because no providerConfig has been saved yet. The app intentionally reports as disabled until valid JSON is entered in the new Provider Config field at Settings > Apps > dotAI > SYSTEM_HOST. Once you paste and save your JSON, dotAI will return to active. If you don't see the new Provider Config (JSON) field at all, clear your browser cache and reload.
Can I use different providers or API keys for chat, embeddings, and image?
Yes. Each section (chat, embeddings, image) declares its own provider and apiKey independently. This is one of the main reasons the format changed — previously, a single shared key was used for all operations. You can now mix and match providers, use separate keys for billing or scoping purposes, or omit sections you don't use entirely.
How do I verify whether per-site or SYSTEM_HOST configuration is being applied to a given site?
Call GET /api/v1/ai/completions/config?siteId=your-site-id and check the configHost field in the response. If configHost returns the target site's hostname, the per-site config is active. If it returns SYSTEM_HOST, the site is inheriting from the system default — meaning no per-site providerConfig has been saved for it.