# How to identify read-only Historian providers?

**URL:** <https://forum.inductiveautomation.com/t/how-to-identify-read-only-historian-providers/112354>\
**Category:** Module Development\
**Created:** [November 21, 2025, 10:26am UTC](https://forum.inductiveautomation.com/t/how-to-identify-read-only-historian-providers/112354 "2025-11-21T10:26:27Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![e.sagnelonge](https://avatars.discourse-cdn.com/v4/letter/e/7cd45c/32.png) [@e.sagnelonge](https://forum.inductiveautomation.com/u/e.sagnelonge)\
**Post date:** [November 21, 2025, 10:26am UTC](https://forum.inductiveautomation.com/t/how-to-identify-read-only-historian-providers/112354/1 "2025-11-21T10:26:27Z")

</div>

Some historian providers like the DB Table Historian (WideDbHistorian) or the Simulator Historian (SimulatorHistorian) do not accept history writes.

In the Tag Actor, in Java, valid historians for storage are identified as follows:

```java
public void configureTagModel(MutableConfigurationPropertyModel model) {
    TagHistoryProps.register(model);
    List<String> names = this.manager.getHistorianNames().stream()
        .filter(name -> this.manager.getStorageEngine(name).isPresent())
        .toList();
    model.setAllowedValues(TagHistoryProps.HistoryProvider, names);
}

```

One of our modules has a gateway config page (Web UI) where you can select a historian, etc. However, I can’t find any information that distinguishes a read-only historian provider from another.  
Some of them expose a **storage** metric, but it doesn’t seem reliable to base this on that property, since some historians might not manage/report this metric.

See this route:

[http://localhost:8088/data/api/v1/resources/list/com.inductiveautomation.historian/historian-provider](http://localhost:8088/data/api/v1/resources/list/com.inductiveautomation.historian/historian-provider)

Another route returns the list of historian types, but all historians report **canCreate =\> true.**

[http://localhost:8088/data/api/v1/resources/type/com.inductiveautomation.historian/historian-provider](http://localhost:8088/data/api/v1/resources/type/com.inductiveautomation.historian/historian-provider)

Does anyone know if this information is exposed natively via one of the OpenAPI routes (without having to re-implement this logic)?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [November 21, 2025, 2:01pm UTC](https://forum.inductiveautomation.com/t/how-to-identify-read-only-historian-providers/112354/2 "2025-11-21T14:01:18Z")

</div>

That is what the `filter` is doing. For each history provider name, it tests if the same-named storage engine exists.

---

<div class="post-metadata">

**Author:** ![e.sagnelonge](https://avatars.discourse-cdn.com/v4/letter/e/7cd45c/32.png) [@e.sagnelonge](https://forum.inductiveautomation.com/u/e.sagnelonge)\
**Post date:** [November 21, 2025, 2:22pm UTC](https://forum.inductiveautomation.com/t/how-to-identify-read-only-historian-providers/112354/3 "2025-11-21T14:22:32Z")

</div>

That’s not really what I was asking.  
I already understand what the filter is doing on the Java side.  
My question was mainly whether any of the OpenAPI routes expose this information explicitly (read-only vs write-capable), so that I don’t have to re-implement the same logic in our module.

From what I’ve seen so far, it doesn’t look like this information is exposed, but I wanted to double-check in case I’m overlooking something.

---

<div class="post-metadata">

**Author:** ![e.sagnelonge](https://avatars.discourse-cdn.com/v4/letter/e/7cd45c/32.png) [@e.sagnelonge](https://forum.inductiveautomation.com/u/e.sagnelonge)\
**Post date:** [November 21, 2025, 2:29pm UTC](https://forum.inductiveautomation.com/t/how-to-identify-read-only-historian-providers/112354/4 "2025-11-21T14:29:14Z")

</div>

Here’s what I ended up implementing:

1. I copied the same mechanism used by the Tag Actor into a utility class.

```java
public class HistorianUtils {
    public static Object getTagHistoryProviders(RequestContext requestContext, HttpServletResponse httpServletResponse){
        JsonArray histories = new JsonArray();

        HistorianManagerImpl m = HistorianGatewayHook.get(SyncManager.gatewayContext).getHistorianManager();
        List<String> names = m.getHistorianNames().stream()
                .filter(name -> m.getStorageEngine(name).isPresent())
                .toList();
        names.forEach(histories::add);

        return histories;
    }
}

```

1. I exposed a route that uses this utility.

```java
@Override
public void mountRouteHandlers(RouteGroup routes) {
    routes.newRoute("/api/v1/xxxx/tag-history-providers")
            .type(RouteGroup.TYPE_JSON)
            .method(HttpMethod.GET)
            .requirePermission(PermissionType.READ)
            .handler(HistorianUtils::getTagHistoryProviders)
            .openApi(api -> api
                    .tag("xxxx")
                    .summary("Tag history providers")
                    .description("Returns the list of tag history providers available on this gateway."))
            .mount();
}

```

Route : [http://localhost:8088/data/sofrel/api/v1/xxxx/tag-history-providers](http://localhost:8088/data/sofrel/api/v1/xxxx/tag-history-providers)

---

<div class="post-metadata">

**Author:** ![paul-griffith](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/paul-griffith/32/37249_2.png) [@paul-griffith](https://forum.inductiveautomation.com/u/paul-griffith)\
**Post date:** [November 21, 2025, 4:29pm UTC](https://forum.inductiveautomation.com/t/how-to-identify-read-only-historian-providers/112354/5 "2025-11-21T16:29:23Z")

</div>

> [@e.sagnelonge](#):
>
> canCreate =\> true.

Yeah, the `/api/v1/resources/` endpoints are common to all resource types that register a meta. So the `canCreate` here is just saying that new instances of the type can be created; not the same as the question you're asking.

There's only one bespoke route created by the historian module at the moment, and it's just used to list remote history providers. I think your workaround is the way to go.
