From Unity to Grafana
Before proceeding, make sure you meet the requirements and have completed the base configuration.
This documentation explains the integration process between Unity WebGL and Grafana dashboards using custom events.\ The main goal is to send interaction data from Unity (e.g., clicked objects) to Grafana, so dashboards can dynamically update and visualize DT information.
In Unity
Creating a JavaScript Library (JSLib)
To enable communication between Unity and Grafana, create a .jslib file inside the directory:
Assets/Plugins/WebGL
The folder names must match exactly. If any folder is missing, create it manually, otherwise the plugin will not work.
The JSLib file structure should be:
mergeInto(LibraryManager.library, {
<eventName>: function (<paramName>) {
dispatchReactUnityEvent(
"<eventName>",
<paramName>);
}
});
Example JSLib file
mergeInto(LibraryManager.library, {
GetData: function (deviceId) {
dispatchReactUnityEvent(
"GetData",
Pointer_stringify(deviceId));
}
});
- The first parameter (
"GetData"
) is the event name (<eventName>
). It is recommended (but not required) that this matches the function name. - The second parameter (
deviceId
) matches the function parameter (<paramName>
).- For strings, wrap with
Pointer_stringify
to ensure correct transmission. (an integer will be sent otherwise) - For numeric values, you can pass the parameter directly without conversion.
- For strings, wrap with
Sending Events
Inside a Unity C# script, declare the external method to call the JSLib function.
This must be placed inside the class, but outside methods such as Start()
or Update()
:
#if UNITY_WEBGL && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern void GetData(string deviceId);
#else
private static void GetData(string deviceId){
Debug.Log("No data");
}
#endif
- In WebGL builds,
GetData
is imported from the JavaScript plugin. - In Unity Editor, a placeholder is defined to prevent runtime errors.
Example usage
Sending the identifier of a GameObject
to Grafana:
void SendEventWithId(GameObject go){
if(go != null){
GetData(go.name);
}
}
Complete script example
Detect clicks on 3D objects and send the object name to Grafana:
using System.Runtime.InteropServices;
using UnityEngine;
public class ObjectClicker : MonoBehaviour
{
#if UNITY_WEBGL && !UNITY_EDITOR
[DllImport("__Internal")]
private static extern void GetData(string deviceId);
#else
private static void GetData(string deviceId){
Debug.Log("No data");
}
#endif
void Update(){
if (Input.GetMouseButtonDown(0)){
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out RaycastHit hit, 100.0f)){
if (hit.transform != null){
SendEventWithId(hit.transform.gameObject);
}
}
}
}
void SendEventWithId(GameObject go){
if(go != null){
GetData(go.name);
}
}
}
If this script is attached to the Main Camera, then whenever a user clicks on a Unity object, the object's name will be dispatched as a GetData
event to Grafana.
This is an example using object clicks in Unity, but events can be triggered from any Unity action and from any GameObject.
In Grafana
Creating a variable
You must create a variable of type Text Box or Constant to receive the value sent from Unity.
- Open
Dashboard Settings
. - Go to Variables → click
New variable
. - Select Text Box or Constant as type.
- Enter the variable name (e.g., thingId).
- (Optional) If using Text Box, you can configure Show on dashboard → Nothing to hide the variable from end users. For debugging, it is recommended to keep it visible and hide it later if necessary.
- Click
Apply
→Save Dashboard
.
Configuring the panel
In the Grafana panel, configure the Receive data from Unity section by adding a new event:
- Event name (e.g.,
GetData
). - Data type expected.
- Variable to update (the one created earlier).
For more details on available modes and configuration fields, see the Unity plugin options documentation.
Using the Variable in Queries
The Unity GetData
event dynamically updates the Grafana variable. You can use it directly in queries:
from(bucket: "opentwins")
|> range(start: v.timeRangeStart, stop: v.timeRangeStop)
|> filter(fn: (r) => r["_measurement"] == "mqtt_consumer")
|> filter(fn: (r) => r["thingId"] == "${thingId}")
|> keep(columns: ["_time", "_value", "_field"])
Here, ${thingId}
will update automatically based on Unity interactions.