The SPFA puts new nodes into the queue every time it sees a "better" edge to minimize your total distance, which is just Bellman-Ford's with better pruning. Bellman-Ford's Algorithm has proven that non-negative-weighted cycles have a maximum of |V| - 1 edges.
Thus, to check if a cycle is negatively-weighted, you just need to check if you used at least |V| edges during the run of your SPFA. In other words, check if you visited the same node at least |V| times.
Here's an appended pseudocode:
procedure SPFA(G, s)
for each vertex v ≠ s in V(G)
d(v) := ∞
visits(v) := 0
d(s) := 0
push s into Q
while Q is not empty
u := pop Q
visits(u) := visits(u) + 1 // increment visit count
if visits(u) < |V| then // relaxation step
for each edge (u, v) in E(G)
if d(u) + w(u, v) < d(v) then
d(v) := d(u) + w(u, v)
if v is not in Q then
push v into Q
However, note that this won't get all nodes that are part of a negative-weight cycle. To get all nodes that are part of negative-weight cycles, do a DFS or BFS to mark all nodes reachable from u, where visits(u) = |V|.
Here's the final modified pseudocode:
procedure DFS(G, u, visited)
if visited(u) = false then
visited(u) := true
for each edge (u, v) in E(G)
DFS(G, v, visited)
procedure SPFA(G, s)
for each vertex v ≠ s in V(G)
d(v) := ∞
visits(v) := 0
d(s) := 0
push s into Q
while Q is not empty
u := pop Q
visits(u) := visits(u) + 1 // increment visit count
if visits(u) < |V| then // relaxation step
for each edge (u, v) in E(G)
if d(u) + w(u, v) < d(v) then
d(v) := d(u) + w(u, v)
if v is not in Q then
push v into Q
for each vertex u in V(G)
visited(u) := false
for each vertex u in V(G), where visits(u) = |V|
DFS(G, u, visited)
for each vertex u in V(G), where visited(u) = true
d(u) := -∞