Raw Data Export Example Script

Hi,

I have taken the time to get my game uploading all kinds of wonderful data and so far so good.

Now i would like to export that data and get it displaying so i can start drawing my own comparisons. The Unity Manual on Raw data exports seems to assume a lot of prior knowledge that im simply not understanding where to begin.

Im simply looking to

  1. Export data (Using The REST API so i can perform the task from code).
  2. Assign a field from that data to a variable.

Does anyone have an example of this they would be willing to share?

Thank you in advance.

Greetings Pixtopher,

My name is Skeledurr.

I have attached an example script that you can study to learn how to download export data from Unity. Please keep in mind the script requires a Json library and Unity.IO.Compress. Links below.

Unfortunately for this example I used JsonDotNet ($25 purchase from the asset store):

But I’m sure you can find any other free examples and use it instead.

Simple Json is a great alternative.
http://wiki.unity3d.com/index.php/SimpleJSON

Unity.IO.Compress. (This is a free download)

I have attached the example script to this post. Please let me know if you have any questions.

Many kind regards,
Skeledurr

p.s Can’t wait for Dungeon League to be released.

using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using Unity.IO.Compression;
using UnityEngine;


public class RawDataGetExample : MonoBehaviour
{
    private const string PROJECT_ID = ""; // Find this in your Analytics dash board / Configure / Project ID
    private const string API_KEY = ""; // Find this in your Analytics dash board / Configure / Raw Data Export API Key
    private const string BASE_URL = "https://analytics.cloud.unity3d.com";


    public List<string> curRequestIds = new List<string>();
    private float timeSinceLastCheck = 0;
    private float checkRate = 5f;




    private void Start()
    {
        CreateExport("2017-01-01", "2017-01-05", "appStart");
    }

    private void Update()
    {
        if(Time.time - timeSinceLastCheck > checkRate)
        {
            timeSinceLastCheck = Time.time;
            CheckRequests();
        }
    }



    // ************************
    //      CREATE EXPORT
    // ************************

    // Tell Unity to create us a file with all the data we want on the server.
    private void CreateExport(string startDate, string endDate, string dataSet)
    {
        Debug.Log("Start create export request.");
        string postUrl = BASE_URL + "/api/v2/projects/" + PROJECT_ID + "/rawdataexports";
       
        Dictionary<string, string> headers = new Dictionary<string, string>();
        headers.Add("Authorization", "Basic " +
            System.Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(PROJECT_ID+":"+ API_KEY)));

        headers.Add("Method", "POST");
        headers.Add("Content-Type", "application/json");


        Dictionary<string, object> dict = new Dictionary<string, object>();
        dict.Add("startDate", startDate);
        dict.Add("endDate", endDate);
        dict.Add("format", "json");
        dict.Add("dataset", dataSet);
        string data = JsonConvert.SerializeObject(dict);
        Debug.Log(data);


        WWW request = new WWW(postUrl, System.Text.Encoding.ASCII.GetBytes(data), headers);
       
        StartCoroutine(WaitForRequest(request));
    }



    // ************************
    //       PROCESS POST
    // ************************

    // When our request is complete process it.
    private void ProcessRequest(ReceivedData receivedData)
    {
        // If the file generation has completed on the server. Download it!
        if (receivedData.status == "completed")
        {
            if (curRequestIds.Contains(receivedData.id)) curRequestIds.Remove(receivedData.id);

            Download(receivedData);
        }
        // If the file generation is still running. Add the id to our request ids.
        // We will check on it again later.
        else if (!curRequestIds.Contains(receivedData.id))
        {
            curRequestIds.Add(receivedData.id);
        }
    }



    // ************************
    //      CHECK REQUESTS
    // ************************

    // Check current requests.
    private void CheckRequests()
    {
        for(int i = 0; i < curRequestIds.Count; i++)
        {
            GetExportStatus(curRequestIds[i]);
        }
    }



    // ************************
    //           GET
    // ************************

    // Check the status of a current export request.
    private void GetExportStatus(string requestId)
    {
        Debug.Log("Check status of request - id: " + requestId);

        string getUrl = BASE_URL + "/api/v2/projects/" + PROJECT_ID + "/rawdataexports/"+ requestId;

        Dictionary<string, string> headers = new Dictionary<string, string>();
        headers.Add("Authorization", "Basic " +
            System.Convert.ToBase64String(System.Text.Encoding.ASCII.GetBytes(PROJECT_ID + ":" + API_KEY)));


        WWW request = new WWW(getUrl, null, headers);

        StartCoroutine(WaitForRequest(request));
    }



    // ************************
    //      REQUEST PROCESS
    // ************************

    IEnumerator WaitForRequest(WWW www)
    {
        yield return www;

        // check for errors
        if (www.error == null)
        {
            Debug.Log("WWW Ok!: " + www.data);

            ReceivedData receivedData = JsonConvert.DeserializeObject<ReceivedData>(www.data);
            ProcessRequest(receivedData);
        }
        else
        {
            Debug.Log("WWW Error: " + www.error);
        }
    }


    // ************************
    //      DOWNLOAD FILE
    // ************************

    // Download file from Unity.
    private void Download(ReceivedData receivedData)
    {
        Debug.Log("Download file - id: "+ receivedData.id+", fileList.Length: "+ receivedData.result.fileList.Length);

        StartCoroutine(DownloadProcess(receivedData.id, receivedData.result.fileList[0].url));
    }
   
    IEnumerator DownloadFileList(ReceivedData receivedData)
    {
        Debug.Log("Starting to download file list - file count: " + receivedData.result.fileList.Length);

        for(int i = 0; i < receivedData.result.fileList.Length; i++)
        {
            yield return StartCoroutine(DownloadProcess(receivedData.id, receivedData.result.fileList[i].url));
        }

        Debug.Log("Download file list complete.");
    }

    IEnumerator DownloadProcess(string dataId, string downloadUrl)
    {
        Debug.Log("Starting download - id: " + dataId);

        WWW www = new WWW(downloadUrl);

        while(!www.isDone)
        {
            yield return null;
        }

        Debug.Log("Download complete - id: " + dataId);

        string fullPath = Application.dataPath + "/"+ dataId+".gzip";
        File.WriteAllBytes(fullPath, www.bytes);

        Debug.Log("Decompressing file");

        byte[] file = File.ReadAllBytes(fullPath);
        byte[] decompress = Decompress(file);
        string text = System.Text.ASCIIEncoding.ASCII.GetString(decompress);
        HandleFileContents(text);
    }


    // ************************
    //      DECOMPRESS FILE
    // ************************
   
    static byte[] Decompress(byte[] gzip)
    {
        // Create a GZIP stream with decompression mode.
        // ... Then create a buffer and write into while reading from the GZIP stream.
        using (GZipStream stream = new GZipStream(new MemoryStream(gzip),
            CompressionMode.Decompress))
        {
            const int size = 4096;
            byte[] buffer = new byte[size];
            using (MemoryStream memory = new MemoryStream())
            {
                int count = 0;
                do
                {
                    count = stream.Read(buffer, 0, size);
                    if (count > 0)
                    {
                        memory.Write(buffer, 0, count);
                    }
                }
                while (count > 0);
                return memory.ToArray();
            }
        }
    }


    // ************************
    //   HANDLE FILE CONTENTS
    // ************************

    // Handle what ever you want to do with the data here.
    private void HandleFileContents(string jsonFromFile)
    {
        Debug.Log("file contents: " + jsonFromFile);
    }



    // *******************
    //      UTILITY
    // *******************

    // Lazy class for deserializing the json from the server.
    // Update the properties if you want to get different data.
    public class ReceivedData
    {
        public string id;
        public string status;

        public Results result;

        public class Results
        {
            public Files[] fileList;
        }

        public class Files
        {
            public string name;
            public string url;
        }
    }
}

2996745–223279–RawDataGetExample.cs (7.54 KB)

11 Likes

Thank you so much Skeledurr!

Your response should totally get pinned as an example for future noobies.

Brilliant - thank you so much. Works like a charm so far.

You can also download the Raw Data Export files directly from the Analytics Dashboard. RDE does require a Pro license.

Hi @Skeledurr_1 ,

thanks for your script. It works in the Editor and if I create an .exe application.
I would like to get it running as WebGL version, so I can trigger it from anywhere. I get
“WWW Error: Unknown error”
when running the app on my server. It seems to be CORS related. I read a lot about it, e.g.

So the question is if Unity (https://analytics.cloud.unity3d.com) supports CORS, right? Anything else I could test or do?
Thanks

UPDATE: Tried again in browser and this is what Chrome reports:

For me this looks like there’s no CORS support on the unity cloud subdomain. I’ll create a separate thread and ask for it.

Instead of your approach, I might instead suggest a server-side scripting/web service api solution that does not require CORS. You could access the service from anywhere as a web service, and would not require CORS.

Hi,
I am using this script for post request but every time i got the Bad Request Error 400.
I want my Analytics data within unity.
any solutions.!!

It would be difficult to say what is wrong without knowing what the request looks like. I trust you have it working using curl as mentioned in the documentation? You don’t want to call the API from within a game.

Question: how do you decipher the submit time string?

1 Like

is “ts” also a date?

Sorry if these are covered in an FAQ. If there is a page I can read please let me know.

Yes, ts = timestamp . This may help https://docs.unity3d.com/Manual/UnityAnalyticsRawDataExport.html

1 Like

Do events get pushed in chunks? I am seeing submit times that are all the same.

Yes, they get sent in batches

1 Like

ok great :slight_smile: thanks for the info!