diff --git a/ivette/api/plugins/dive/index.ts b/ivette/api/plugins/dive/index.ts
index a63a701b04eb6ea0516c8cea456b014f3df5c3c7..b1e2c48ddcccd6edb1f670193decea3cc8039f21 100644
--- a/ivette/api/plugins/dive/index.ts
+++ b/ivette/api/plugins/dive/index.ts
@@ -93,11 +93,11 @@ export const jNodeIdSafe: Json.Safe<nodeId> =
 /** Natural order for `nodeId` */
 export const byNodeId: Compare.Order<nodeId> = Compare.number;
 
-/** The callstack context for a node */
-export type callstack = { fun: string, instr: number | string };
+/** A callsite */
+export type callsite = { fun: string, instr: number | string };
 
-/** Loose decoder for `callstack` */
-export const jCallstack: Json.Loose<callstack> =
+/** Loose decoder for `callsite` */
+export const jCallsite: Json.Loose<callsite> =
   Json.jObject({
     fun: Json.jFail(Json.jString,'String expected'),
     instr: Json.jFail(
@@ -105,18 +105,32 @@ export const jCallstack: Json.Loose<callstack> =
              'Union expected'),
   });
 
-/** Safe decoder for `callstack` */
-export const jCallstackSafe: Json.Safe<callstack> =
-  Json.jFail(jCallstack,'Callstack expected');
+/** Safe decoder for `callsite` */
+export const jCallsiteSafe: Json.Safe<callsite> =
+  Json.jFail(jCallsite,'Callsite expected');
 
-/** Natural order for `callstack` */
-export const byCallstack: Compare.Order<callstack> =
+/** Natural order for `callsite` */
+export const byCallsite: Compare.Order<callsite> =
   Compare.byFields
     <{ fun: string, instr: number | string }>({
     fun: Compare.string,
     instr: Compare.structural,
   });
 
+/** The callstack context for a node */
+export type callstack = callsite[];
+
+/** Safe decoder for `callstack` */
+export const jCallstackSafe: Json.Safe<callstack> =
+  Json.jArray(jCallsiteSafe);
+
+/** Loose decoder for `callstack` */
+export const jCallstack: Json.Loose<callstack> = Json.jTry(jCallstackSafe);
+
+/** Natural order for `callstack` */
+export const byCallstack: Compare.Order<callstack> =
+  Compare.array(byCallsite);
+
 /** The description of a node locality */
 export type nodeLocality = { file: string, callstack?: callstack };
 
diff --git a/ivette/src/frama-c/dive/Dive.tsx b/ivette/src/frama-c/dive/Dive.tsx
index bfc4056e79ac8648ef4e017c4747c4112cdff243..7edc9f8da8bd47f5d6a73541e7663131255b2c24 100644
--- a/ivette/src/frama-c/dive/Dive.tsx
+++ b/ivette/src/frama-c/dive/Dive.tsx
@@ -36,7 +36,7 @@ interface CytoscapeExtended extends Cytoscape.Core {
   cxtmenu(options: any): void;
 }
 
-function callstackToString(callstack: API.callstack[]): string {
+function callstackToString(callstack: API.callstack): string {
   return callstack.map((cs) => `${cs.fun}:${cs.instr}`).join('/');
 }
 
@@ -139,8 +139,7 @@ class Dive {
     return this.cy.add({ data: { id, label: fileName }, classes: 'file' });
   }
 
-  referenceCallstack(callstack: API.callstack[]): Cytoscape.NodeSingular | null
-  {
+  referenceCallstack(callstack: API.callstack): Cytoscape.NodeSingular | null {
     const name = callstackToString(callstack);
     const elt = callstack.shift();
 
diff --git a/src/plugins/dive/server_interface.ml b/src/plugins/dive/server_interface.ml
index 71a309b3c1ed02a21ead8bd1594f1444be8d5385..0bd290f0608a3cf8d647480f03386158d5eaf152 100644
--- a/src/plugins/dive/server_interface.ml
+++ b/src/plugins/dive/server_interface.ml
@@ -151,16 +151,23 @@ struct
       Data.failure "no node '%d' in the current graph" node_key
 end
 
-module Callstack =
+module Callsite =
 struct
-  let name = "callstack"
-  let descr = Markdown.plain "The callstack context for a node"
+  let name = "callsite"
+  let descr = Markdown.plain "A callsite"
   let jtype = Data.declare ~package ~name ~descr (Jrecord [
       "fun", Jstring;
       "instr", Junion [ Jnumber ; Jstring ];
     ])
 end
 
+module Callstack =
+struct
+  let name = "callstack"
+  let descr = Markdown.plain "The callstack context for a node"
+  let jtype = Data.declare ~package ~name ~descr (Jarray Callsite.jtype)
+end
+
 module NodeLocality =
 struct
   let name = "nodeLocality"