changed(integer change)

The changed event is invoked when operations change certain properties of the prim/object. The change parameter is a bit field of one or more of the following values:

Constant Value Indicates  
CHANGED_INVENTORY 0x1 changed object inventory (could include an item being added, removed, or renamed, or a notecard being edited and saved). Details
CHANGED_COLOR 0x2 changed object color or transparency  
CHANGED_SHAPE 0x4 changed object shape (box to cylinder, for example), cut, hollow amount/shape, twist, top size, or shear  
CHANGED_SCALE 0x8 changed object scale. Details
CHANGED_TEXTURE 0x10 changed object texture: offset, repeats, rotation, and reflection/bump maps (but not transparency — that’s CHANGED_COLOR). Also triggered when the glow status of the object is changed.  
CHANGED_LINK 0x20 linking or delinking (also when an avatar sits on or unsits from the object). Details
CHANGED_ALLOWED_DROP 0x40 An item was dropped (into this object’s inventory) that was only allowed by the llAllowInventoryDrop function. This allows the object to identify items dropped by anyone who doesn’t have modify permissions on the object.  
CHANGED_OWNER 0x80 The ownership of the object changed. This value is passed when an object is deeded to a group, when an object is purchased, or when a newly-purchased object is rezzed. Details
CHANGED_REGION 0x100 The object changed regions/sims. Details
CHANGED_TELEPORT 0x200 The object has been teleported. Details
CHANGED_REGION_START 0x400 The region this object is in has just come online.  
CHANGED_MEDIA 0x800 The prim media has changed.  


These values are bitwise and can be ORed or ANDed together.
Two flags can show up in the same event trigger; it has been seen when resizing an object with the “Stretch Textures” box unchecked so the texture scale (repeats) changes as the prim is resized. Also, the CHANGED_REGION and CHANGED_TELEPORT seem to come in tandem.With this in mind, always write “if (change & CHANGED_LINK)” rather than “if (change == CHANGED_LINK)” so that the contents of your event will be triggered in all cases. Likewise, using IF/ELSEs (as in “else if (change & CHANGED_SCALE)“) could theoretically result in only one of the triggers being counted. If you stick to with IF statements only, your changed event will need to perform a check for each IF statement, but it will catch all triggers in the very rare event of a simultaneous trigger.


  • The change parameter describes only what type of change happened, not the difference between the original and changed versions of the object. If you need to determine exactly what changed, the script must store the relevant properties and compare the values from before and after the change.
  • Prim/object position and rotation are not currently detected when changed but can be via a timer and llGetRot and llGetPos. Position changes can also be detected by using the moving_start and moving_end events.
  • When an avatar sits on an object, they seem to become part of the linkset.
  • changed() event is raised with CHANGED_LINK as the parameter when an avatar sits on an object or un-sits. To find out what happened, use llAvatarOnSitTarget which returns the NULL_KEY if no avatar is sitting on the object, or the key of the avatar that is sitting at the sit target.


// When an avatar sits on the object containing this script,
// the object will say "Get off!" and then force the avatar to stand up.
default {
    state_entry() {
        llSitTarget(<0, 0, 0.1>, ZERO_ROTATION); // needed for llAvatarOnSitTarget to work
    changed(integer change) { // something changed
        if (change & CHANGED_LINK) { // and it was a link change
           // llSleep(0.5); // llUnSit works better with this delay
            key av = llAvatarOnSitTarget();
            if (av) { // somebody is sitting on me
                llSay(0, "Get off!"); // say in chat when person is remove from prim
                llUnSit(av); // unsit him


Constant or Value: changed() is triggered: changed() is not triggered:
  • when adding any inventory item to the prim’s inventory.
  • when deleting any inventory item from the prim’s inventory.
  • when changing the name or description of an inventory item inside the prim.
  • when changing asset permissions of an inventory item within the prim.
  • when saving a notecard that already exists within the prim’s inventory.
  • when recompiling a script that already exists in the prim’s inventory.
  • when inventory is changed in another prim in the linked object.
  • when resetting a script.
  • when a no-copy item is removed (but not deleted!) from the prim by manually dragged back to user inventory.
  • when inventory is added using llAllowInventoryDrop, and the user dropping the new inventory item is not the owner of the prim.
  • when the change is invoked via LSL llRemoveInventory(..). This may be a bug, see: http://jira.secondlife.com/browse/SVC-304
  • in a prim, linked or not, when resizing that prim. (as of 5/6/2008, resizing a child prim causes CHANGED_SCALE in the *root* prim — LexNeva)
  • in the root prim in a linked object when resizing the entire object.
  • in a different prim in a linked object when resizing a separate prim in that object.
  • in a child prim in a linked object when resizing the entire object.
  • when linking two (or more) prims together.
  • when delinking an object.
  • when delinking a prim from an object.
  • when an avatar sits on an object.
  • when a sitting avatar stands up from the object.
  • when duplicating a linked object.
  • When changing the prim type/shape of a prim in the object.
  • in an attachment when an avatar sits down or stands up.
  • in an attachment when it’s attached.
  • in an attachment when another attachment is attached.
  • in an attachment when you sit on an object.
  • in an object when the sitting avatar attaches an object.
  • when duplicating a single prim.
  • in the original object when a user buys the object.
  • in the original object when a user buys a copy of the object.
  • in the original object when a user takes the object or a copy of the object.
  • in the newly-rezzed copy when the user rezzes the object for the first time. (on_rez() is still triggered first.) This occurs whether or not the object was copied or purchased.
  • when an object is deeded to a group.
  • in the original object when the user buys the contents of an object. It is still triggered in the copy when the new owner rezzes it.
  • in the root prim of an attachment when the user teleports to a new sim/region or crosses into a new sim directly.
  • in the root prim of an object that moves into a new region.
  • in a child prim of an attachment when the user teleports to a new region.
  • in a child prim of an object that moves into a new region.
  • after taking the object into inventory, moving/teleporting to a new region and rezzing it there – it is only triggered if the object moves into a new region while it is rezzed
  • in the root prim of an attachment when the user teleports to a new sim, or a location within the current sim. This happens whether they teleport manually, or using one of the teleport functions.
  • in a child prim of an attachment when the user teleports to a different location.
  • in any prim in an attachment when the user sits on an object that uses the llSitTarget “sit teleport” trick.
  • in any prim in an unattached object.
  • in an attachment, after teleporting to no-script land, not even being entered into the event queue. This means it will not be triggered after teleporting to a region where scripts are allowed, only the event for that teleport will be triggered.

(As of Second Life 1.16.0 (5) this is not accurate. Teleporting into no-script land will cause the event to trigger once you move onto script-enabled land, as though you had just teleported.)

Aside from the above, the changed() event is also not triggered:

  • when an object changes position. (Use moving_start() and moving_end().)
  • when an object changes rotation.
  • when changing the object’s name or description.
  • when changing the object’s group. (not deeding the object to a group — that’ll trigger CHANGED_OWNER)
  • when toggling “Share with group”, “Allow anyone to move”, “Allow anyone to copy”, setting the object “For Sale”, changing any of the sale settings, or setting “Next owner can:”.
  • when toggling “Lock”, “Physics”, “Temporary” or “Phantom”.
  • when setting prim’s material.
  • when setting prim’s light properties.
  • when using llSetText.
  • when using llParticleSystem.
  • in a worn attachment when the owner attaches or detaches it. (Use attach().)
  • in a worn attachment when the wearer sits on something.
  • when the object is selected/edited.

This script uses the changed event with a few other functions to see which notecard was updated, added, or deleted

//written by Ruthven Willenov, added to lslwiki 9/23/2009
list notes;
list ids;
integer note = INVENTORY_NOTECARD;

        integer tot = llGetInventoryNumber(note);
        integer i = 0;
        for(i;i < tot;++i)
                string name = llGetInventoryName(note,i);
                key id = llGetInventoryKey(name);
                integer index = llListFindList((list)name,notes);
                if(index = -1 )
                    notes += name;
                    ids += id;
                    llOwnerSay("Added notecard named: " + name);
    changed(integer change)
        if(change & CHANGED_INVENTORY)
            integer tot = llGetInventoryNumber(note);
            integer i = 0;
            for(i;i < tot;++i)
                string name = llGetInventoryName(note,i);
                key id = llGetInventoryKey(name);
                integer index = llListFindList(notes,(list)name);
                if(index == -1 )
                    notes += name;
                    ids += id;
                    llOwnerSay("Added notecard named: " + name);
                if(index >= 0)
                    if(llList2Key(ids,index) != id)
                        ids = llDeleteSubList(ids,index,index);
                        ids = llListInsertList(ids,(list)id,index);
                        llOwnerSay(name + " was updated");
            integer len = llGetListLength(notes)-1;
            for(len; len >= 0; --len)
                string name = llList2String(notes,len);
                integer type = llGetInventoryType(name);
                if(type == -1)
                    llOwnerSay(name + " was removed.");
                    notes = llDeleteSubList(notes,len,len);
                    ids = llDeleteSubList(ids,len,len);


Q and A:

Q: How do I find out when my object has changed position or rotation?
A: You can’t, not by using changed(). The moving_start() and moving_end() event handlers are triggered when the object is moved. To find out when the object is rotated, your best option is to use a timer. (Unless, of course, your object is an attachment, in which case, it will never merely rotate, but will change position constantly, triggering moving_start() and moving_end().)
Q: Regarding bitwise operations: it says above that scale and textures “have been seen” changing at the same time. Does that mean that both CHANGED_TEXTURE and CHANGED_SCALE will always be triggered while scaling a texture with an object?
A: Not necessarily, it just means that they occasionally will be triggered together. You can’t predict when this will happen, or even if it will. Make your code able to deal with all possibilities. Assumptions will often produce code that fails, with little indication as to why. As it says above, always write “if (change & CHANGED_LINK)” rather than “if (change == CHANGED_LINK)” so that the contents of your event will be triggered in all cases.
Q: Is there a way to detect when a user buys an object?
A: Yes. Specifying CHANGED_OWNER for change will let you filter the results of changed(). See the details section for specifics.
To detect when a user pays an object, you want the money() event handler.
Q: Is there a way to be notified via an event when a script is added or removed from the object’s inventory?
A1: No. Your only option is to use a timer to regularly compare the current inventory to a list of preexisting scripts.
A2: “The above answer is wrong. Use CHANGED_INVENTORY to compare the current inventory to a list of preexisting scripts, not a timer.”
A3: “Both answers are correct. You can detect when something gets added with a changed event, but NOT when it gets removed. It needs a timer to detect removals.”
Q: Can I use the detection functions (llDetected*) with changed()?
A: No, they only work with touches, collisons and sensors.
Q: Can I find out who (or what) caused the object to change?
A: Not intrinsically, but this can be programmed.  One can compare parameters/states/keys/features of an object before and after the changed event to determine what caused the change. For example, to find out what changed the inventory of a prim, first on initialization (state_entry), get the UUID keys of the existing contents using llGetInventoryKey() and store to a variable. When an item is edited and saved it is assigned a new key and the changed event occurs. Compare the new key of the item using llGetInventoryKey() to the previously stored key. If the key’s match the item is unchanged. If the keys do not match we know what item changed the prim’s inventory.  For CHANGED_OWNER, compare new owner key to previous owner key.  For CHANGED_SCALE compare the previous scale to the new scale, etc.  One can also determine what event triggered the change event by a debug llSay/llOwnerSay message in the event. Example, a touch causes a scale change.