Table of Contents
Optimizely Fotoware add-on (version 5.5) for Optimizely CMS 12 and .NET 8
Learn how to install, configure, and use the Optimizely Fotoware add-on for Optimizely CMS 12 and .NET 8.
Table of Contents
Feature
This article explains how to install, configure, and use the Optimizely Fotoware add-on (version 5.0 or later). For a version that works with Optimizely CMS 13 and .NET 10, see Optimizely Fotoware add-on (version 1) for Optimizely CMS 13 and .NET 10.
The export widget will work without a Server API License, but will not synchronize metadata; it will only download the image to Optimizely.
Before you start
This article is technical and requires knowledge of the Optimizely ecosystem. To set up and configure the add-on, we recommend getting assistance from someone experienced with Optimizely integrations.
Example Image Property and selection dialog from Fotoware

Example: TinyMce Toolbox button
.png)
How it works
When an asset is selected, the asset is imported into the default Optimizely asset management repository and used in an image property (of type ContentReference or Url) or the Rich Text editor. There is also an Optimizely scheduled job (to be enabled after installation) that keeps the imported images and metadata in Optimizely up to date when they change in Fotoware.
Key features of the integration:
- Easy to add to Optimizely solutions, both new and existing solutions.
- The integration can be removed without affecting the used assets.
- Used assets from Fotoware are synchronized into Optimizely's default asset management, making it easy for developers familiar with Optimizely to get started.
- It is possible to configure media to show only local assets, only assets from Fotoware, or both.
- Developers can configure their own media models containing the metadata to be synchronized with Fotoware.
- Since downloaded media become standard Optimizely media items, Optimizely keeps track of which media is used where in the solution.
Note: Versions 1, 2, and 3 only support importing static images, such as .jpg files. PDFs may work, but are not meant to. Video, .svg files, and animated gifs are not currently supported.
Installation
You can find information on Nuget.optimizely.com: https://nuget.optimizely.com/package/?id=Fotoware.PlugIns.Optimizely (external link)
Installing and configuring the add-on takes less than one hour.
Dependencies
This version of the add-on requires at least EPiServer.CMS.UI 12.
The add-on automatically adds support for Optimizely Commerce and works on version 14 and higher.
Version 3 of EPiServer.CMS.TinyMCE is needed for the Toolbox button in the editor.
Registering the Selection Widget integration with Fotoware
Before setting up the Optimizely integration, you must register the application in the Fotoware Site Configuration.
From the Tools menu (cogwheel icon), go to Site Configuration > Integrations > Applications.
Select Add application to set up the Selection Widget integration.
.jpg)
Type: Select Web App / API and API (as in the example above).
Name: Enter the name of the application - for example, Optimizely integration
Redirect URIs: Set the URI the user is returned to after authentication completes. The redirect URI is usually in the form:
http(s)://domain.com/*episerver*/fotoware.plugins.episerver/authentication/callback
Whether or not /episerver is part of the URI depends on how Optimizely has been configured. The redirect URI should be set in the Integrations settings above. Use small caps. In a multi-site scenario, one URI is needed per domain.
User consent: Use markdown syntax to add any custom information that should be displayed when the user uses the plugin for the first time. It's also possible to include a link to a privacy policy.
Access: This is used to control who has access to use the plugin.
Client ID / Client Secret: These values are auto-generated when you select Save (see the example below). Copy both values to a temporary location, such as a text file. Later, you must add these to the web.config file of the Optimizely plug-in, in Fotoware:ClientIdand Fotoware:ClientSecret value fields (See web.config section below).
Once you have done this, you can delete the text file. If you lose the client secret, you can generate a new one and update the web.config file.
.png)
Registering the Server-to-Server integration
Next, you must register a server-to-server authentication to complete the integration. This can be obtained in the Fotoware Site Configuration: Log in to your Fotoware tenant, open the Tools menu (cogwheel), and select Site configuration. The integration settings are found in the Integrations node, under Applications.
Add a new application and set the Type to Non-interactive/script, as seen in the screenshot below.

Name the integration and select Save to generate the Client ID and Client secret values. Copy them to a working document and insert them in the Optimizely web.config file in the Fotoware:ServerApi:ClientId and Fotoware:ServerApi:ClientSecretvalue fields (see below).
Configuration
Startup and appsettings.json:
Add services.AddFotowarePlugin(); into your startup.cs
```
public void ConfigureServices(IServiceCollection services)
{
//at the end
services.AddFotowarePlugin();
}
```
```
"Fotoware": {
<!-- all these data is to be obtained from Fotoware -->
<!-- Documentation ClientId and Secret for Selection widget https://learn.fotoware.com/Integrati..._authorization -->
"ClientId": "[Enter your Fotoware guid]",
"ClientSecret": "[Enter your client secret string]",
<!-- Documentation for ServerApi ClientID and Secret https://learn.fotoware.com/Integrati...with_OAuth_2.0 -->
"ServerApi": {
"ClientId": "[Enter your Fotoware guid]",
"ClientSecret": "[Enter your client secret string]"
},
<!-- Leave RedirectUri empty or remove if nothing else is told to you. Domain is not required in Optimizely multisite solution,
example https://domain.com/*episerver*/Fotow...ation/callback
or use default /episserver/fotoware.plugins.optimizely/authentication/callback
where *episerver* is depending on your configuration. CASE SENSITIVE, use LOWER CASE -->
"RedirectUri": "/episerver/fotoware.plugins.optimizely/authentication/callback",
"TenantUrl": "https://my.fotoware.cloud",
<!-- which asset folder to import images to -->
"RootFolderId": "[Enter an id to a media folder in Optimizely where you want downloaded assets, for instance 218]",
<!-- presets is used to predefine a width of an image to download, can be used with Fotoware:PreferredDownloadWidth, presets are defined in Fotoware -->
"PresetUrl": "/fotoweb/me/presets/export/[your presets guid]",
<!-- these are optional -->
<!-- EnableOnAllImages default is "true" -->
/*"EnableOnAllImages": "false",*/
/* ExportWidgetEnableOnAllImages default is "true" */
/*"ExportWidgetEnableOnAllImages": "false",*/
/* DisableEpiserverDefaultMediaSelector default is "false" */
/*"DisableEpiserverDefaultMediaSelector": "true",*/
"AllowedTypes": ".jpg,.jpeg,.jpe,.gif,.bmp,.png,.gif,.psd",
/* PreferredDownloadWidth is important to be same or less than the presets width to work, zero is default and will den take the default presets width */
"PreferredDownloadWidth": "1600",
/* Refresh token valid for days, then user need to login again, default is 14 */
"RefreshToken": {
"ValidDays": "1"
}
/*"ArchiveUrlsToSynchronize": "/fotoware/archives/5000-Archive,/fotoware/archives/5000-Archive-2",*/ }
"ImportOriginalSelection": true, //Add dropdown value "Import Original" selection on Image Property, will always download the original image thru the Download API, bypassing the presets.
"DisableAssetPane": false,//disabling right click in asset panel folders
```It is also possible to implement and register an instance of the IFotowareSettings (or extended IFotowareCommerceSettings) interface to take full control of all settings, for instance, configuring which metadata to synchronize.
Configuring additional settings
You need to implement the IFotowareMedia interface on a content type that inherits from the Optimizely ImageData class in your solution. This will enable additional fields used by the add-on to keep assets in sync with the originals in Fotoware.
|
|
|
(The FotowareModifiedDate property is used to track when the asset was last changed in Fotoware.
Note: An update to the metadata of an asset in Fotoware only adds 2 seconds to the modified date; therefore, we need to keep track of this date and time.
Add to your Tiny MCE configuration toolbar
The button is automatically plugged into Tiny MCE. If it doesn't show up, you probably already have a custom configuration. In startup.cs, add **fotoware-insert-media** to your toolbar.
Decorate your Optimizely Property with the Fotoware UIHint attribute:
|
|
|
This will replace Optimizely's built-in image editor with an extended editor that supports selecting images from Fotoware and local Optimizely images.
To disable the option to select local images in Optimizely, you can add another attribute to your property:
**FotowareConfigurationAttribute** is introduced in version 2. `[FotowareConfiguration(DisableDefaultEpiserverMedia = true, ExportWidgetEnabled = WidgetStatus.Disabled, /* only with XhtmlString, will use the export url from fotoware direct, instead of downloading the asset to Optimizely */ UseExportUrlOnly = false, QueryParameters = "crop=false&enhance=false&caption=false&action=false&publication=false&behaviour=false")]`
The attribute should be used in combination with FotowareUiHint. The parameters are documented here Integrati...gets#section_7.
Scheduled jobs
There are 2 jobs:
- **Fotoware - Synchronize assets**: Normally enabled if you want to sync updates from Fotoware to Optimizely. This job will only update assets if the assets have been updated in Fotoware.
- **Fotoware - Synchronize assets - Force**: As above, but will always download the latest image and metadata. Only to be run manually if needed.

Synchronizing metadata from Fotoware to Optimizely
The add-on supports synchronizing metadata between Fotoware and Optimizely through a mapping schema defined in your implementation of the **IFotowareSettings** interface. Implement your own **IFotowareSettings** and define the mapping schema for the metadata you want to include in the Optimizely assets.
Note: Some default metadata is included in Fotoware, but this can be extended for each client.
The default mapping schema is set up as follows:
|
|
|
The mapping schema has keys that match the metadata names in Fotoware, and the values are the property names in Optimizely.
Note: The types need to be the same when changing the configuration; for instance, Photographers is a list of strings.
You can find the default keys here: Fotoware_...MP_field_codes
The following example shows how to add custom metadata to the synchronization:
|
|
|
Controlling the structure of downloaded assets in Optimizely [Optional]
Since Fotoware stores assets in a flat list and Optimizely uses a hierarchical structure, assets imported to Optimizely are placed in a folder structure. This helps when browsing the imported assets and avoids a long list of assets in the same folder, which Optimizely does not handle well. It is possible to manage the folder structure for assets in Optimizely. By default, folders are created based on the year and month the asset was imported into Optimizely, but you can use other structures, for instance, based on metadata in the solution.
This is achieved by implementing the **IFolderResolver** interface.
If you want to save the image to "For this page", register this in the startup.services.AddScoped<IFolderResolver, ForThisPageFolderResolver>();
Customize Tiny MCE HTML template [Optional]
You can implement your own input HTML when inserting in Tiny MCE, for example, by filling in the alt-text or adding some CSS classes.
This is done by implementing and registering an implementation of **IFotowareTinyMceTemplateResolver** where you override GetHtml(ContentReference contentReference, string insertingToContentReference=null).
Event handling with Fotoware events
Available events are:
- OnImageDownloading: Raised before downloading an asset with the possibility to cancel the action.
- OnImageDownloaded: Raised after the asset has been downloaded.
- OnImageDeleted: Raised in the synchronization job when an asset is deleted or revoked in Fotoware.
The following example shows how to register event handlers for these events in an InitializationModule:
|
|
|
Disabling the Fotoware plugin in Optimizely Commerce Asset list
Implement and register IFotowareCommerceSettings.PreventCommerceEditorIntegration.
By default, this is enabled.
Logging Fotoware.Plugins.Optimizely
The add-on includes logging information that can be used for information and debugging the integration.
Extras: code samples
In the NuGet package under Tools, you can find some code samples of IFolderResolver, IFotowareSettings, and IFotowareTinyMceTemplateResolver implementations, as well as additional scheduled jobs for synchronizing entire archives from Fotoware.
Troubleshooting
Tip: Turn on Logging Fotoware.Plugins.Optimizely.
Multi-site configuration
From version 3.5 and later, you can have different Fotoware instances for different sites in Optimizely.
You must implement the IFotowareConfig interface.
Example: For each site
|
|
|
It will revert to the default IFotowareSettings set globally if siteid is not found.
Known issues
An error occurred when sending the request - This is probably due to the handshake with the endpoint not working. Make sure you use Tls12.
Note: The callback URL is case-sensitive. Check your URL. Best practice is to use lowercase.
Fotoware Optimizely/Episerver Plugin Change Log
## 5.5.0 - dec 2024
Update: targeting .NET 8
NEW FEATURE: Right-click folder in Asset panel, "Import from Fotoware"
CONFIG: "DisableAssetPane": false,//disabling right click in asset panel folders
NEW FEATURE: IFolderResolver now can save to "For this page", to change default behavior, add services.AddSingleton<IFolderResolver, ForThisPageFolderResolver>() in startup
BREAKING: If you use any custom IFolderResolver, you can now save to "For this page", you need to add "string currentPageId" for the method GetAssetFolder
## 5.4.2.0 - dec 2023
Adding a dropdown value "Import Original" to the Image Property will always download the original image via the Download API, bypassing the presets.
"Fotoware": {
"ImportOriginalSelection": true
}
Add to TinyMCE **fotoware-insert-original** to your toolbar if wanted
Add localization, put XML in lang folder: (example Norsk)
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<languages>
<language name="Norsk" id="no">
<episerver>
<cms>
<widget>
<thumbnailselector>
<importfotowaretitle>Importere fra Fotoware</importfotowaretitle>
<importfotoware>Importere original</importfotoware>
</thumbnailselector>
</widget>
</cms>
</episerver>
</language>
</languages>
__________________________
## 5.3.0.0 - oct 2023
Add download API to SVG, PDF, GIF, and PNG, making it possible to download these extensions + transparent PNG + animated GIFs
Newer Dojo Dialog window
Tested with EPiServer.CMS.TinyMce version 4.4.1 and Episerver.CMS 12.22.3
"AllowedTypes": ".jpg,.jpeg,.jpe,.gif,.bmp,.png,.gif,.psd,.svg,.pdf"
New configs to disable Export Widgets: "Fotoware:FilesNotOpenInExportApi": ".svg,.gif,.pdf", //default if not set => .png,.svg,.gif,.pdf
## 5.2.0.0 - apr 2023
Compatibility with EPiServer.CMS.TinyMce version 4.1.
Update to the new thumbnail selector in Optimizely.
Fixed bug where environment appsettings were not used.
Added the possibility to have IFotowareMedia side by side with non-FotowareMedia.
## 5.0.0.5 - dec 2022
## 5.0.0.0 - mar 2022
Compatibility with .NET 5 and Optimizely CMS 12 and Commerce 14
[Breaking change] From now on, the package name is Fotoware.Plugins.Optimizely (just change namespace everywhere)
## 3.6.0.1 - jan 2022
#4734 [BUG] using widget import not working without export widget enabled
## 3.6.0.0 - may 2021
#3799 Use Export URL directly in WYSIWYG, without downloading the asset in Optimizely
## 3.5.0.0 - apr 2021
#3632 Multisite configuration - you can now have different Fotoware instances per site in Optimizely
#2985 Fotoware login token expiry (default 14 days)
## 3.0.0.1 - mar 2021
#3634 [BUG] Cookie is set as httpOnly from web.config <httpCookies httpOnlyCookies="true" requireSSL="true" />, javascript cant read, popup opens and closes several times
## 3.0.0.0 - jan 2021
[Breaking] Fotoware:ApiToken in appsetting is now removed and replaced with Fotoware:ServerApi:ClientId and Fotoware:ServerApi:ClientSecret.
#1749 Use Oauth server to server API authentication
#2926 You can now run the plugin with Export Widget without a Server API License, then the asset is transferred, but not the metadata.
## 2.2.0.0 - nov 06, 2020 (not public)
Last version with Fotoware:ApiToken configuration. Version 3 introduces the OAuth server to server authentication
#392 [BUG] Image property is not updated in Optimizely. Change the window dialog popup against the Optimizely JavaScript modal window.
#2967 [BUG] Server error not showing if custom error page is enabled on the server
## 2.1.0.0 - june 07, 2020
#1800 [BUG] Images like PSD, are saved with PSD in the name, but should be saved as export format (jpg)
#1905 [Bug] TinyMCE is always opening ExportWidget, disregarding the config
#1904 [BUG] TemplateResolver for TinyMce is not triggered
## 2.0.4.0 - may 15, 2020
#1747 Access token not fetched caused a loop
#1748 Images with åäö not working
#844 cookie login user specific
## 2.0.0.0 - jan 10, 2020
#391 Support for Export Widget
New - FotowareConfigurationAttribute
## 1.3.0.2 - 2019-10-17
#388 Better logging and error messages
## 1.3.0.0 - 2019-10-07
BUGS
#306 [Bug] Reloading existing synced images didn't allow publishing
#307 [Bug] Drag n drop from Windows didn't work on FotowareThumbnailSelector
NEW FEATURES
#136 Enable Fotoware integration on all UIHint Image settings by default (config)
#137 Change download procedure to always download the latest assets if changed
## 1.0.2.0 - 2019-09-18
#278 [BUG] Enable Custom Domains. Pagescripts validating the domain against fotoweb.cloud, this is removed
##initial release 1.0.1.0 - 2019-06-01