Page 1 of 1

Roblox Collision Summaries API Explained (October 2026): Fields, Impact Speed, and the Network Ownership Trap

Posted: Thu Oct 22, 2026 5:12 pm
by ice
Quick Summary
  • Roblox added

    Code: Select all

    BasePart:BindToCollisionSummaries(callback)
    on October 6, 2026. It hands your code the contact point, unit normal, relative velocity, and contact area for every collision your part had in a frame, data that the

    Code: Select all

    Touched
    event does not carry.
  • It is a separate API from

    Code: Select all

    BasePart.Touched
    . Roblox explicitly says it is not meant to be called from inside a

    Code: Select all

    Touched
    event.
  • The callback runs at most once per frame, after the physics step finishes. Processing cost scales with how many parts you subscribe, not with how many collisions happen in the scene.
  • Summaries are generated where physics runs and nothing is replicated. If another client needs to know, you process the summary and fire your own remote event.
  • The old workarounds still have their place.

    Code: Select all

    Touched
    remains the cheap signal that something happened, and raycasts or velocity checks stay useful when you only need an approximation and want no subscription overhead.
What the API Actually Gives You

The October 6 announcement from the Roblox Physics Team frames the problem bluntly: until now you had two choices if you wanted to know how two parts collided.

Code: Select all

Touched
tells you that a collision occurred, but not where, not in what direction, and not with how much impact energy. The alternative was faking it with velocity checks and raycasts.

Code: Select all

BindToCollisionSummaries
closes that gap with data generated by the physics engine itself. You subscribe one part, and once per frame, after the simulation has stepped, the callback receives an array of summaries describing every contact patch that part was involved in during that frame. Each summary reports where the contact occurred, which direction it faced, and how fast the two parts were moving relative to each other.
The official

Code: Select all

BasePart
reference documents the method as subscribing to detailed per-frame contact data, and notes plainly that it is a separate mechanism from

Code: Select all

BasePart.Touched
.That wording matters, because the two are easy to confuse.

The Callback Signature and Summary Fields

The call takes one argument, a function, and returns an

Code: Select all

RBXScriptConnection
that you disconnect to end the subscription:

Code: Select all

BasePart:BindToCollisionSummaries(callback: (summaries: {CollisionSummary}) -> ()) -> RBXScriptConnection
Each summary is a frozen, immutable table with these keys:
  • Time (number): simulation time, in seconds, of the physics substep that produced this summary. Use it to order multiple summaries delivered in one callback.
  • Part0 (BasePart): the subscribed part, the one you called the method on.
  • Part1 (BasePart): the other part in the pair, which may be Terrain.
  • Point (Vector3): contact point in world space, averaged across the points in the patch.
  • Normal (Vector3): unit contact normal for the patch, oriented relative to the subscribed part.
  • RelativeVelocity (Vector3): velocity of Part1 relative to Part0 at the contact point.
  • Area (number): estimated contact patch area in square studs. It reads 0 for a patch of fewer than three points, such as an edge or corner contact.
Two behaviours in that table are worth calling out because they surprise people.

The

Code: Select all

Normal
is oriented relative to your subscribed part, not relative to whichever part the engine happened to list first. So if both parts of a pair are subscribed, each subscription receives its own summary with itself as

Code: Select all

Part0
and the normal flipped to match.That is convenient, but it means you cannot assume the normal direction is consistent across two subscribers without checking which one you are.

Code: Select all

RelativeVelocity
is measured before the collision is resolved by the solver. The magnitude of its projection onto

Code: Select all

Normal
is the speed at which the two parts are approaching or separating head-on, and the component tangential to

Code: Select all

Normal
describes sliding and glancing contact.If you want something force-like, the docs point you to

Code: Select all

AssemblyMass
on the parts.
Reading Impact Speed and Detecting Glancing Hits

The example Roblox shipped is impact-based visual effects. Dot the relative velocity against the normal, compare it to a threshold, and spawn sparks at the contact point:

Code: Select all

local function onCollision(summaries)
    for _, s in summaries do
        local impactSpeed = s.RelativeVelocity:Dot(s.Normal)
        if impactSpeed > 10 then
            spawnSparks(s.Point, s.Normal, impactSpeed)
        end
    end
end

local connection = car.Chassis:BindToCollisionSummaries(onCollision)

-- and when you are done with it:
connection:Disconnect()
The same pattern covers impact audio, tire marks and scuffs, damage models weighted by where a hit landed, and combat hit detection that needs to know which part of a blade connected.
The Limits, Because They Change How You Design Around Them

The documentation lists the constraints in detail, and several of them are design decisions rather than footnotes.
  • Contact recording is enabled only while at least one subscription exists anywhere in the

    Code: Select all

    Workspace
    , and the cost scales with the number of subscribed parts rather than the total number of collisions in the scene.
  • Contacts between two sleeping parts produce no summaries. A part that is asleep stops reporting until it wakes again.
  • Parts with

    Code: Select all

    CanCollide = false
    produce no summaries.
  • Physics may run several substeps per frame, so a pair that stays in contact across several of them produces up to one summary per patch per substep, all delivered in the same callback invocation. Sort or sum by

    Code: Select all

    Time
    if the ordering matters to you.
  • Non-convex collision geometry produces one summary per pair of touching convex hulls, and terrain contact is split further by contact normal, so either can yield several summaries for the same pair within one substep.
  • Nothing is replicated. Each client generates summaries for the collisions it owns.
  • Destroying the part disconnects its subscriptions automatically.
  • The method throws an error if the callback is nil, or if the part is not a descendant of

    Code: Select all

    Workspace
    .
The Network Ownership Problem, and It Is the Big One

This is the part the announcement leads into indirectly and that most scripts get wrong on the first try. Summaries are generated on the network owner where the physics simulation executes, client or server, and nothing is replicated across the network. If another client needs to know about a collision, you process the summary and fire your own remote event with just what you need.
Roblox distributes physics between the server and connected clients, and it assigns network ownership of simulated

Code: Select all

BasePart
s to either side to divide the work. By default the server retains ownership, anchored parts are always server-owned and you cannot change that, and the engine auto-assigns ownership of unanchored parts to a client based on hardware capacity and proximity to the player character.
That gives you two failure modes to design against.

If the colliding part is owned by a client, your summary fires on that client, not the server. A server-side damage script listening for summaries on a player-owned part will simply never see them.

The opposite problem is worse for security. Roblox states that clients can exploit client ownership by sending bad data to the server, for instance teleporting a

Code: Select all

BasePart
, pushing it through walls, or making it fly. It also states that

Code: Select all

BasePart.Touched
events are tied to network ownership, meaning a client can fire

Code: Select all

Touched
on a part it owns and send it to the server even if the server does not see it touch anything. A client can make a sword deal damage across the map by firing the event through script injection, which is why Roblox says to check the validity of such events fired by clients.

Code: Select all

BindToCollisionSummaries
does not fix that. It inherits the same trust boundary because it reports from wherever physics runs. Server-authoritative hit validation, distance checks, and rate limits stay necessary.

How It Compares to the Older Approaches

The three options are not interchangeable, and picking the wrong one is how you end up with either a laggy feel or a silent bug. Side by side:
  • Touched, what you get: the other part, and the start and end of contact. Nothing about where or how hard.
  • Touched, what it costs: nothing to leave in place, but it is tied to network ownership, so a client can fire it for a part it owns.
  • Velocity checks and raycasts, what you get: a position, a hit, or a number you derive yourself. No contact point, no normal, no true impact energy.
  • Velocity checks and raycasts, what they cost: whatever you spend each frame in the loop, on any part regardless of ownership.
  • BindToCollisionSummaries, what you get: the averaged contact point, the unit normal, the relative velocity at contact, and the estimated patch area, straight from the solver.
  • BindToCollisionSummaries, what it costs: one subscription per part you care about, and Roblox states that cost scales with the subscribed parts rather than with the total collisions in the scene.
  • Where each runs: Touched fires on the network owner of the part. Raycasts run wherever you call them. Collision summaries run on the network owner of the physics simulation, and nothing is replicated.
  • Trust boundary: all three are untrusted on a client-owned part. Roblox says to check the validity of events fired by clients, and that warning covers collision summaries as much as it covers Touched.
  • Pick Touched when: a trigger zone only needs to know something touched it.
  • Pick raycasts or velocity checks when: you need a cheap approximation and the part may be owned by anyone.
  • Pick BindToCollisionSummaries when: you need the contact point, the normal, or a real impact speed, and you can subscribe the part that matters.
Roblox's own guidance in the announcement is that processing overhead scales only with the number of subscribed parts, not with the total number of collisions in the scene. That is the argument for subscribing selectively: a handful of weapon parts, a vehicle chassis, a few key hazards, rather than every part in the place.
A Practical Migration Checklist
  1. Decide which side of the network needs the data. If it is the server and the part is client-owned, you are processing summaries on the client and firing a remote event yourself.
  2. Call

    Code: Select all

    BindToCollisionSummaries
    on the parts you care about and keep the returned

    Code: Select all

    RBXScriptConnection
    so you can disconnect it.
  3. Handle multiple summaries per callback. Sort by

    Code: Select all

    Time
    if you need substep ordering.
  4. Use

    Code: Select all

    RelativeVelocity:Dot(Normal)
    for head-on impact speed, and the tangential component for glancing or sliding contact.
  5. Treat

    Code: Select all

    Area = 0
    as an edge or corner contact, not as a missing value.
  6. Do not rely on the callback for anything that must be trusted. Validate on the server.
  7. Disconnect subscriptions when a part is destroyed or no longer needed. Destroying the part already disconnects them, but explicit cleanup keeps the count of subscribed parts predictable.
FAQ

Can I call BindToCollisionSummaries inside a Touched event?
No. Roblox states the API is not designed to be called from within a

Code: Select all

Touched
touch event. It is a separate API for getting collision information.If you want contact detail, subscribe directly to the part instead.

Does it replace BasePart.Touched?
No.

Code: Select all

Touched
still fires on contact start and end, still tells you which part touched yours, and still costs nothing to leave in place. What changes is that you no longer need

Code: Select all

Touched
plus a raycast plus a velocity guess to work out where and how hard something hit.
Why did I get no callback for a part that was resting on the ground?
Contacts between two sleeping parts are not recorded. A part that goes to sleep stops producing summaries until it wakes. Parts with

Code: Select all

CanCollide = false
also produce nothing.
Can a server script read summaries for a part a client is simulating?
No. Summaries are generated where the physics simulation executes and nothing is replicated. If another client needs to know, process the summary locally and fire your own remote event with just the data you need.
Will subscribing slow my game down?
Roblox says the overhead scales with the number of subscribed parts, not with the total number of collisions in the scene. Subscribing a few hundred parts is not the same as subscribing every part in the workspace, so pick deliberately.
What does Area = 0 mean?
A contact patch of fewer than three points, such as an edge or a corner contact. It is a real contact with an estimated area below what the engine reports, not a bug in your code.

Sources