HELP
Scripting Advanced Published: 2026-03-17  |  ← Back to School

Alife Virtual School - Class 16: JSON Data Handling in LSL

JSON Data Handling in LSL — Alife Virtual School

JSON Data Handling in LSL — Free class in Alife Virtual School

Unlock the Power of Web APIs and Structured Data in Alife Virtual

Welcome, scripters, to a class that will fundamentally change how you build and interact with the world—both inside and outside of Alife Virtual. You’ve mastered variables, functions, and events. Now, it’s time to teach your scripts to speak the universal language of the internet: JSON.

Imagine a weather system on your island that displays real-time, live weather from a city of your choice. Picture a vendor that pulls product information directly from a website, or a game that posts high scores to an online leaderboard. These aren't just futuristic dreams; they are practical applications you can build today, and JSON (JavaScript Object Notation) is the key that unlocks them all. In Alife Virtual, where you get a massive 65,536 sqm private island completely free, the potential for creating complex, data-driven experiences is limitless.

This advanced tutorial will guide you through the essential LSL functions for handling JSON. By mastering this skill, you’ll be able to connect your in-world creations to the endless ocean of data and services available on the web, making your projects smarter, more dynamic, and infinitely more powerful. And since Alife Virtual offers full LSL scripting support, identical to Second Life, the skills you learn here are not only powerful but also completely transferable.

What You Will Learn

Prerequisites

This is an Advanced scripting class. Before you begin, you should be comfortable with the following LSL concepts. If you need a refresher, please feel free to browse our other free daily classes at the Alife Virtual School!


Main Tutorial: From Zero to JSON Hero

Let's get our hands dirty. The best way to learn is by doing. We'll start with the basics and build up to a fully functional example you can create right on your own land.

Step 1: Understanding the JSON Format

At its heart, JSON is just a text format for structuring data. It’s easy for humans to read and for machines to parse. It consists of two main structures:

  1. Objects: A collection of key/value pairs, enclosed in curly braces {}. Keys are strings in double quotes, followed by a colon, then the value.
  2. Arrays: An ordered list of values, enclosed in square brackets [].

Here’s a simple JSON object representing a user profile:

string userProfile = "{
  \"username\": \"Trinity\",
  \"level\": 42,
  \"isOnline\": true,
  \"inventory\": [\"Sword\", \"Shield\", \"Health Potion\"]
}";

Notice the keys ("username", "level") and their corresponding values. The value for "inventory" is a JSON array of strings.

Step 2: Reading Data with llJsonGetValue()

This is your primary tool for extracting information from a JSON string. It takes two arguments: the JSON string to parse and a "path" string that specifies which value you want.

The syntax for the path is simple:

Let's use the userProfile string from above to see it in action. Create a new script in a prim and paste this code into it:


default
{
    state_entry()
    {
        llSay(0, "Ready to parse JSON. Touch me to begin.");
    }

    touch_start(integer total_number)
    {
        // Our sample JSON data
        string userProfile = "{ \"username\": \"Trinity\", \"level\": 42, \"isOnline\": true, \"inventory\": [\"Sword\", \"Shield\", \"Health Potion\"] }";

        // 1. Get the username
        string username = llJsonGetValue(userProfile, ["username"]); // Path is ".username"
        llOwnerSay("Username: " + username);

        // 2. Get the level
        string level = llJsonGetValue(userProfile, ["level"]); // Path is ".level"
        llOwnerSay("Level: " + level);

        // 3. Get the first inventory item
        string firstItem = llJsonGetValue(userProfile, ["inventory", "0"]); // Path is ".inventory[0]"
        llOwnerSay("First inventory item: " + firstItem);

        // 4. What happens if the path is wrong?
        string invalidData = llJsonGetValue(userProfile, ["nonexistentKey"]); // Path is ".nonexistentKey"
        if (invalidData == JSON_INVALID)
        {
            llOwnerSay("The key 'nonexistentKey' was not found!");
        }
    }
}

Save the script. When you touch the object, it will parse the JSON and report the values to you in local chat. Notice the important check for JSON_INVALID. Always check for this to handle cases where the data you're looking for doesn't exist.

Pro Tip: llJsonGetValue always returns a string. If you retrieve a number or boolean, you'll need to cast it to the correct type for calculations or logic, like (integer)level or (integer)isOnline.

Step 3: Building and Modifying Data with llJsonSetValue()

While reading data is useful, creating and changing it is where the real power lies. llJsonSetValue() lets you build a JSON string from the ground up or modify an existing one.

It's crucial to remember that LSL strings are immutable. This means llJsonSetValue() does not change the original string. Instead, it returns a new string with the modification. You must assign this new string back to your variable.

Let's expand on our previous example. We'll start with an empty JSON object and build it piece by piece.


default
{
    state_entry()
    {
        llSay(0, "Touch to build a JSON string.");
    }

    touch_start(integer total_number)
    {
        // Start with an empty JSON object
        string myJson = "{}";
        llOwnerSay("Initial JSON: " + myJson);

        // Add a name
        myJson = llJsonSetValue(myJson, ["name"], "My Awesome Object");
        llOwnerSay("After adding name: " + myJson);

        // Add a creator
        key ownerKey = llGetOwner();
        myJson = llJsonSetValue(myJson, ["creator_key"], (string)ownerKey);
        llOwnerSay("After adding creator: " + myJson);

        // Add a list of features as a JSON array
        // To add to an array, use empty brackets [] in the path
        myJson = llJsonSetValue(myJson, ["features", ""], "Glows"); // Appends "Glows"
        myJson = llJsonSetValue(myJson, ["features", ""], "Rotates"); // Appends "Rotates"
        llOwnerSay("Final JSON: " + myJson);

        // Let's modify an existing value
        myJson = llJsonSetValue(myJson, ["name"], "My SUPER Awesome Object");
        llOwnerSay("Modified JSON: " + myJson);
    }
}

Save and touch the object. Watch the local chat as your script constructs a JSON string step-by-step. This is the fundamental technique for preparing data to send to an external API.

Step 4: The Easy Way - llList2Json()

Building JSON with `llJsonSetValue` can be repetitive. For simpler structures, `llList2Json` is a fantastic shortcut. It converts an LSL list into a JSON string in one command.

It has two modes:


default
{
    state_entry()
    {
        // Example 1: Creating a JSON Array
        list simpleList = ["Apple", "Banana", "Cherry"];
        string jsonArray = llList2Json(JSON_ARRAY, simpleList);
        // Result: "[\"Apple\",\"Banana\",\"Cherry\"]"
        llOwnerSay("JSON Array: " + jsonArray);


        // Example 2: Creating a JSON Object
        list objectList = ["name", "Data Orb", "version", 1.2, "active", TRUE];
        string jsonObject = llList2Json(JSON_OBJECT, objectList);
        // Result: "{\"name\":\"Data Orb\",\"version\":1.2,\"active\":true}"
        llOwnerSay("JSON Object: " + jsonObject);
    }
}

This is incredibly efficient for creating configuration data or simple API payloads.

Step 5: Real-World Application: A Live Weather Display

Let's put it all together. We'll create an object that fetches the live weather for a specific location and displays it. For this, we'll use the free Open-Meteo API, which requires no API key for basic use.

Our goal:

  1. Send an llHTTPRequest to the Open-Meteo API.
  2. In the http_response event, receive the weather data as a JSON string.
  3. Use llJsonGetValue to parse the temperature and weather code.
  4. Display this information using llSetText.

This is the kind of project that truly comes to life on your free island, where you have 10,000 prims to build with. You could create an entire village where each house displays weather from a different part of the world!

Create a new script in a prim:


// --- CONFIGURATION ---
// Latitude and Longitude for New York City
float gLatitude = 40.71;
float gLongitude = -74.01;
// --- END CONFIGURATION ---

key gRequestID; // To store the ID of our HTTP request

// Function to convert weather code to a description
string getWeatherDescription(integer code)
{
    if (code == 0) return "Clear sky";
    if (code == 1 || code == 2 || code == 3) return "Mainly clear";
    if (code == 45 || code == 48) return "Fog";
    if (code >= 51 && code <= 57) return "Drizzle";
    if (code >= 61 && code <= 67) return "Rain";
    if (code >= 71 && code <= 77) return "Snowfall";
    if (code >= 80 && code <= 82) return "Rain showers";
    if (code >= 95) return "Thunderstorm";
    return "Unknown";
}

// Function to request the weather update
fetchWeather()
{
    llSetText("Fetching weather...", <1,1,1>, 1.0);
    string url = "https://api.open-meteo.com/v1/forecast";
    url += "?latitude=" + (string)gLatitude;
    url += "&longitude=" + (string)gLongitude;
    url += "¤t_weather=true";

    gRequestID = llHTTPRequest(url, [], "");
}

default
{
    state_entry()
    {
        llSetText("Touch to get weather", <1,1,1>, 1.0);
        // Fetch weather on startup
        fetchWeather();
        // And then update every hour
        llSetTimerEvent(3600.0);
    }

    touch_start(integer total_number)
    {
        // Allow manual refresh on touch
        fetchWeather();
    }

    timer()
    {
        fetchWeather();
    }

    http_response(key request_id, integer status, list metadata, string body)
    {
        if (request_id != gRequestID) return; // Not our request

        if (status != 200)
        {
            llSetText("API Error: " + (string)status, <1,0,0>, 1.0);
            return;
        }

        // --- THIS IS THE JSON MAGIC ---
        // Get the temperature
        string temp = llJsonGetValue(body, ["current_weather", "temperature"]);
        // Get the weather code
        string weatherCode = llJsonGetValue(body, ["current_weather", "weathercode"]);

        if (temp == JSON_INVALID || weatherCode == JSON_INVALID)
        {
            llSetText("JSON Parse Error", <1,0,0>, 1.0);
            return;
        }

        // We have the data! Now display it.
        string description = getWeatherDescription((integer)weatherCode);
        string displayText = description + "\n" + temp + " °C";

        llSetText(displayText, <1,1,0>, 1.0);
    }
}

Save this script. The prim will immediately try to fetch the weather. After a moment, it should update to show the current conditions in New York City! You've just built a smart object that communicates with the real world. Imagine what else you can do now that you have this power. And with free texture and mesh uploads in Alife Virtual, you could create a beautiful custom display for your weather station without spending a dime.


Common Mistakes and How to Avoid Them

  1. Forgetting to Re-assign llJsonSetValue's Result:

    Mistake: llJsonSetValue(myJson, ["key"], "value");
    Correct: myJson = llJsonSetValue(myJson, ["key"], "value");
    Remember, the function returns a new string; it doesn't modify the old one.

  2. Ignoring JSON_INVALID:

    Mistake: Assuming llJsonGetValue always succeeds. If the API changes or your path is wrong, your script will get the literal string "json_invalid" and behave incorrectly.
    Correct: Always wrap your llJsonGetValue calls in an if statement to check for JSON_INVALID and handle the error gracefully.

  3. Incorrect Path Syntax:

    Mistake: Using dots for array indices (e.g., .inventory.0) or brackets for object keys.
    Correct: In LSL, the path is a list. Use ["inventory", "0"] for nested access. The dot/bracket notation is a concept; the list is the implementation.

  4. Data Type Mismatches:

    Mistake: Trying to do math with the string result of llJsonGetValue, e.g., llJsonGetValue(json, ["level"]) + 1. This will perform string concatenation ("42" + 1 -> "421").
    Correct: Cast the result to the proper type first: (integer)llJsonGetValue(json, ["level"]) + 1.

Advanced Tips and Tricks

Practice Exercise: The Interactive Business Card

Now it's your turn to build something! This exercise will test your ability to both build and parse JSON.

  1. Create a simple prim object, your "business card".
  2. Write a script that, when the object is touched, uses llDialog to present a menu with a "Register" button.
  3. When "Register" is clicked, use llListen and llTextBox to ask the user for their name and their favorite color.
  4. Store this information in a well-formed JSON string. For example: {"name":"AvatarName", "favorite_color":"Blue"}.
  5. Save this JSON string into the object's description field using llSetObjectDesc().
  6. Modify the script so that if a user touches the object and their data is already stored, it parses the JSON from the description and says, "Welcome back, AvatarName! I remember your favorite color is Blue."

This is a perfect first project to build on the free private island you get when you join Alife Virtual. With over 1,148,000+ members, you'll have plenty of people to share your creations with!

Frequently Asked Questions (FAQ)

1. Why use JSON instead of a simpler format like comma-separated values (CSV)?
While CSV is fine for simple lists, it cannot represent nested data structures (objects within objects, or lists of objects). JSON is a universal standard understood by nearly every web service and programming language, making it far more versatile and robust for API communication.
2. How do I handle special characters like quotes (") in my data?
You don't have to! The LSL JSON functions handle all the necessary escaping and un-escaping for you automatically. When you use llJsonSetValue("{}", ["name"], "My \"Awesome\" Object"), LSL correctly escapes the quote in the resulting JSON string.
3. Is there a size limit for JSON strings in LSL?
Yes. A JSON string is still an LSL string, so it's subject to the LSL string memory limit, which is quite large but not infinite. For most API calls, this is not a concern. However, if you are handling extremely large datasets, you may need to process them in chunks or request less data from the API.
4. I'm using the Firestorm Viewer. Will these scripts work?
Absolutely! Alife Virtual uses the popular Firestorm Viewer, and our LSL implementation is identical to the one you may be used to. This means all your scripting knowledge and tools work perfectly here, providing a seamless transition for experienced creators.

Summary and Next Steps

Congratulations! You've taken a huge step forward in your LSL scripting journey. You now understand how to create, manipulate, and parse JSON, the language of the web. You can now write scripts that are no longer isolated within the virtual world but can communicate with external services, pull in live data, and create truly interactive and dynamic experiences.

Your next step is to practice. Try the exercise above. Look for public APIs (many are available for free for weather, news, games, and more) and think about how you could integrate them into a project. The more you use these functions, the more natural they will become.

The possibilities are staggering, especially in a world like Alife Virtual that encourages creativity without financial barriers. There are no monthly land fees for your own full region and no upload fees for your content. You have the freedom to build, experiment, and innovate.


Ready to Start Building Your Dream?

There has never been a better time to join the Alife Virtual community. With a free full-body mesh avatar, a free 65,536 sqm private island forever, and a vibrant community of over a million residents, your creative canvas is waiting.

Register your free account today!

Once you've registered, you can immediately claim your own island and start building. Don't forget to check out the full curriculum at the Alife Virtual School to continue your learning journey.

Click here to claim your FREE island and start your new life!


🎓 Ready to Practice In-World?

Get your FREE island and practice everything you just learned — no credit card, no monthly fees.

Claim Your Free Island Now →

No credit card required · Takes 2 minutes · Your island is FREE forever


Published: 2026-03-17 · Difficulty: Advanced · Category: Scripting  |  Questions? Contact us  |  ← Back to School