# Best Practice for dataset storage for gateway scripting and perspective use

**URL:** <https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422>\
**Category:** Ignition\
**Tags:** perspective, ignition81, scripting\
**Created:** [January 20, 2026, 7:00pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422 "2026-01-20T19:00:19Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![Benji\_Park](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Benji\_Park](https://forum.inductiveautomation.com/u/Benji_Park)\
**Post date:** [January 20, 2026, 7:00pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/1 "2026-01-20T19:00:19Z")

</div>

OK so let me set the stage. I’m not very versed with programming and there are still a lot of things I don’t understand. What I’m trying to do is link Ignition with AssetEssentials with their API to send meter readings from PLC tags to Assets in AssetEssentials.

I could hardcode AssetIds and tags into my gateway timer script and loop through my list. I’d rather keep the asset ids and tag association elsewhere so that I can also make an Ignition perspective screen that allows for appending to the data.

My best guess is to use a dataset in a memory tag but I’m really struggling with pointing scripts at a tag based dataset. Is there a better place to keep this type of data which allows iterating through in a gateway script and appending in a perspective session?

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [January 20, 2026, 7:07pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/2 "2026-01-20T19:07:27Z")

</div>

I would store the IDs in a database table and retrieve/update via queries. Share your script for a better understanding of what you are doing and how we can help.

---

<div class="post-metadata">

**Author:** ![Benji\_Park](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Benji\_Park](https://forum.inductiveautomation.com/u/Benji_Park)\
**Post date:** [January 20, 2026, 7:21pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/3 "2026-01-20T19:21:02Z")

</div>

My script so far is a basic API login to get a token.

Then from the AssetEssentials documentation, I would FOR loop through my data and do a series of POST operations with different asset id and meter readings(from plc tags).

**Request URI** : POST `/v2/assets/1/meterreadings`

#### **Request Body**

```python
{
    "DateRead": "2021-03-30T11:09:00",
    "ValueRead": 8,
    "AssetId": 1,
    "MeterTitleId": 2
}

```

So if I understand you correctly, I should go strait to making a table in my database and working with the data that way.

For my understanding, why not use a dataset memory tag and/or what is a better use for a dataset memory tag?

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [January 20, 2026, 7:30pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/4 "2026-01-20T19:30:38Z")

</div>

> [@Benji\_Park](#):
>
> For my understanding, why not use a dataset memory tag and/or what is a better use for a dataset memory tag?

If you want to edit and maintain your data, databases have many features to help you do that. It's easy to add data constraints, such as preventing duplicate values, and provides concurrent access managment, etc for data integrity.

Databases are made for this kind of thing, in other words. Of course, you could use a dataset tag if you wanted.

Make sure to use Ignition's [httpClient](https://docs.inductiveautomation.com/docs/8.1/appendix/scripting-functions/system-net/system-net-httpClient) for the api calls.

---

<div class="post-metadata">

**Author:** ![Benji\_Park](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Benji\_Park](https://forum.inductiveautomation.com/u/Benji_Park)\
**Post date:** [January 20, 2026, 7:33pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/5 "2026-01-20T19:33:38Z")

</div>

Here is what I have so far.

```python
client = system.net.httpClient()

address = "https://assetessentials.dudesolutions.com/Redacted/api"

mydata = {
"LoginName": "Redacted",
"Password": "Redacted",
"CultureCode": "en-US",
"Expires": 1
}

authTolken = client.post(url=address+"/login", data=mydata).text

```

---

<div class="post-metadata">

**Author:** ![dkhayes117](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/dkhayes117/32/68344_2.png) [@dkhayes117](https://forum.inductiveautomation.com/u/dkhayes117)\
**Post date:** [January 20, 2026, 7:41pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/6 "2026-01-20T19:41:23Z")

</div>

Looks reasonable so far.

If this is called often, I like to hold the client in a variable at the top level of a project script (not inside a function). HttpClient objects are heavy weight, don't create it every time you need to use it.

---

<div class="post-metadata">

**Author:** ![Benji\_Park](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Benji\_Park](https://forum.inductiveautomation.com/u/Benji_Park)\
**Post date:** [January 20, 2026, 7:47pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/7 "2026-01-20T19:47:02Z")

</div>

I’m thinking to login, iterate, then logout. I’d run the script every 15 minutes. My guess is that even if I post1000 meter readings, it wouldn’t take more than a minute to run the script and close the httpClient.

---

<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:** [January 20, 2026, 7:51pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/8 "2026-01-20T19:51:24Z")

</div>

> [@Benji\_Park](#):
>
> and close the httpClient.

They don't close by themselves. They are cached, and are expensive to create. Just write your code in a project library script function, and place the assignment to `client` outside the function.

---

<div class="post-metadata">

**Author:** ![Benji\_Park](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Benji\_Park](https://forum.inductiveautomation.com/u/Benji_Park)\
**Post date:** [January 20, 2026, 8:00pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/9 "2026-01-20T20:00:54Z")

</div>

OK, so I write the script in the project library, and it creates the httpClient, logs in, iterates through the post functions to add meter readings, and then logs out. Then I invoke that script from the gateway timer scripts? If so how does one invoke a project library script from the gateway?

---

<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:** [January 20, 2026, 8:02pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/10 "2026-01-20T20:02:15Z")

</div>

The gateway timer event would have the one line:

```python
scriptName.functionName()

```

---

<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:** [January 20, 2026, 8:02pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/11 "2026-01-20T20:02:44Z")

</div>

In the project library:

```python
client = system.net.httpClient()

def doYourApiCall(parameters):
    # do your API call here
    response = client.get()
    return response.json

```

In the gateway timer script, what Phil said.

---

<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:** [January 20, 2026, 8:04pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/12 "2026-01-20T20:04:44Z")

</div>

> [@Benji\_Park](#):
>
> My best guess is to use a dataset in a memory tag but I’m really struggling with pointing scripts at a tag based dataset. Is there a better place to keep this type of data which allows iterating through in a gateway script and appending in a perspective session?

Let's go back to this, though, because maybe there's a better fundamental architecture.

Can you describe in a bit more detail what you're trying to do?  
If you ultimately need this data to live in a _particular_ Perspective session, then tags and gateway timer scripts are (probably) not the right choice.

If you need this data to live globally, totally independent of any Perspective session, then carry on.

---

<div class="post-metadata">

**Author:** ![Benji\_Park](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Benji\_Park](https://forum.inductiveautomation.com/u/Benji_Park)\
**Post date:** [January 20, 2026, 8:32pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/13 "2026-01-20T20:32:37Z")

</div>

I do want this data to live independent of the perspective session. The use of perspective would be to edit what the script is looking at without needing to launch perspective designer.

---

<div class="post-metadata">

**Author:** ![Benji\_Park](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Benji\_Park](https://forum.inductiveautomation.com/u/Benji_Park)\
**Post date:** [January 20, 2026, 8:33pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/14 "2026-01-20T20:33:27Z")

</div>

Thank you for the example code, that helps a lot.

---

<div class="post-metadata">

**Author:** ![Benji\_Park](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Benji\_Park](https://forum.inductiveautomation.com/u/Benji_Park)\
**Post date:** [January 27, 2026, 7:55pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/15 "2026-01-27T19:55:47Z")

</div>

In case this helps anyone else trying to work with the Asset Essentials API, here is my basic working code.

```python
client = system.net.httpClient()

def APICall():
	
	address = "https://assetessentials.dudesolutions.com/REDACTED/api"

	mydata = {
		"LoginName": "Redacted",
		"Password": "Redacted",
		"CultureCode": "en-US",
		"Expires": 2
		}
	
	authToken = client.post(url=address+"/login", data=mydata).text
	
	myheader = {
		"Authorization": "Basic " + authToken
		}
	
	deviceList = [
		{"Asset_Name": "Gator OCA Bearing", "Asset_ID": 2821, "Meter_Title_ID": 103, "Tag_Path": "[default]GATOR1/OCA_Life_km"},
		{"Asset_Name": "Gator OCA Gearbox", "Asset_ID": 2821, "Meter_Title_ID": 104, "Tag_Path": "[default]GATOR1/OCA_Gearbox_Hours"}
		]
	
	for d in deviceList:
		
		Tag_Data = system.tag.readBlocking(d["Tag_Path"])
		
		Tag_Reading = Tag_Data[0]
		
		ReadingTime = system.date.format(Tag_Reading.timestamp, "yyyy-MM-DD'T'HH:mm:ss")
		
		ReadingData = {
			"DateRead": str(ReadingTime),
			"ValueRead": Tag_Reading.value,
			"AssetId": d["Asset_ID"],
			"MeterTitleId": d["Meter_Title_ID"]
			}
		
		MeterReading = client.post(url=address+"/v2/assets/"+str(d["Asset_ID"])+"/meterreadings", headers=myheader, data=ReadingData).text

```

---

<div class="post-metadata">

**Author:** ![lrose](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/lrose/32/62724_2.png) [@lrose](https://forum.inductiveautomation.com/u/lrose)\
**Post date:** [January 27, 2026, 8:54pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/16 "2026-01-27T20:54:37Z")

</div>

I would sugest that you extrapolate the tagpaths into a complete list, and read the values in a single go, rather than each trip through the loop. This is undoubtedly crushing your performance particularly if you have many devices.

I know that right now you only have (or are showing) two devices, but as you add to the list it will become more of an issue. Better to make the code more tolerent now than to wonder why your performace tanks in the future as you add devices.

Something like:

```python
Tag_Data = [qv for qv in system.tag.readBlocking([d['Tag_Path'] for d in deviceList]

for device,reading in zip(deviceList,Tag_Data):
	ReadingTime = system.data.format(reading.timestamp, "yyyy-MM-D'T'HH:mm:ss")
	ReadingData = {
		'DateRead':ReadingTime,
		'ValueRead':reading.value,
		'AssetId':device['Asset_ID'],
		'MeterTitleId':device['Meter_Title_ID']
		}

		MeterReading = client.post(url=address+"/v2/assets/"+str(d["Asset_ID"])+"/meterreadings", headers=myheader, data=ReadingData).text

```

It may seem like looping through the list twice is counter intuitive, but I promise that this will be more performant especially as more devices are added.

---

<div class="post-metadata">

**Author:** ![Benji\_Park](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Benji\_Park](https://forum.inductiveautomation.com/u/Benji_Park)\
**Post date:** [January 27, 2026, 10:48pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/17 "2026-01-27T22:48:42Z")

</div>

Let me start off by saying that I believe you. Could you perhaps explain how it’s more performant? What I see is:

loop:  
read  
read  
read

loop:  
post  
post  
post

**versus**

loop:  
read  
post  
read  
post  
read  
post

If I grow to 2000 devices, it’s still 2000 reads and 2000 posts.

---

<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:** [January 27, 2026, 10:48pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/18 "2026-01-27T22:48:59Z")

</div>

While true in the general case, I'd argue it's far less important here. The time to issue and receive a response from this network call is going to utterly dwarf the time to read an additional tag from a script that's already running on the gateway.

---

<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:** [January 27, 2026, 10:51pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/19 "2026-01-27T22:51:23Z")

</div>

> [@Benji\_Park](#):
>
> how it’s more performant?

Bulk reading is more efficient because it's a single call into the tag subsystem. From the designer or a Vision client, it's **extremely** more efficient, because it's the difference between one network call and N network calls.

But again - I wouldn't worry too much about it here because the call to this external web API is probably going to be orders of magnitude slower than the tag reads. If there's a way to bulk read asset data from this API, _that_ would be worth spending time migrating to.

---

<div class="post-metadata">

**Author:** ![Benji\_Park](https://avatars.discourse-cdn.com/v4/letter/b/5f9b8f/32.png) [@Benji\_Park](https://forum.inductiveautomation.com/u/Benji_Park)\
**Post date:** [January 27, 2026, 10:54pm UTC](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422/20 "2026-01-27T22:54:52Z")

</div>

Thank you, that makes sense.

[Next page](https://forum.inductiveautomation.com/t/best-practice-for-dataset-storage-for-gateway-scripting-and-perspective-use/113422.md?page=2)
