# Ghost/Duplicate CDR Records on Outbound Calls

**URL:** <https://forums.vitalpbx.org/t/ghost-duplicate-cdr-records-on-outbound-calls/6159>\
**Category:** Reporting an Issue\
**Created:** [April 9, 2026, 3:00am UTC](https://forums.vitalpbx.org/t/ghost-duplicate-cdr-records-on-outbound-calls/6159 "2026-04-09T03:00:50Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![MarianGeorge](https://forums.vitalpbx.org/user_avatar/forums.vitalpbx.org/mariangeorge/32/3987_2.png) [@MarianGeorge](https://forums.vitalpbx.org/u/MarianGeorge)\
**Post date:** [April 9, 2026, 3:00am UTC](https://forums.vitalpbx.org/t/ghost-duplicate-cdr-records-on-outbound-calls/6159/1 "2026-04-09T03:00:50Z")

</div>

VitalPBX 4.5.1-6  
Asterisk: 20.15.0

**The problem:**

Unanswered outbound calls generate a duplicate CDR — one real record from `Dial()`, one ghost from the hangup handler. On our system this inflates call stats by 23.5% (1,468 ghost CDRs out of 6,254 outbound in April 2026).

Root cause: `endbeforehexten = yes` closes the real CDR before `exten => h` runs, but the hangup handler ends with `Hangup()` which opens a new empty CDR.

Ghost CDR signature: `lastapp = Hangup`, `duration = 0`, `billsec = 0`, `dstchannel` empty, same `uniqueid` as the real record.

**Reproduce**

1. Make an outbound call, don’t answer it
2. Check CDR — two records, same `uniqueid`

```sql
SELECT uniqueid, COUNT(*) AS cnt,
       GROUP_CONCAT(lastapp ORDER BY sequence) AS apps,
       GROUP_CONCAT(duration ORDER BY sequence) AS durations
FROM asterisk.cdr
WHERE calltype = '3'
  AND calldate >= CURDATE() - INTERVAL 7 DAY
GROUP BY uniqueid
HAVING cnt > 1;

```

**Fix**

Add `NoCDR()` as the first line of `exten => h` in the trunk dial template. The real CDR is already saved, so nothing is lost:

```auto
exten => h,1,NoCDR()
 same => n,System(test -e ${REC_FILENAME})
 ...

```

Would also be nice to have `endbeforehexten` exposed in the GUI or defaulted to `no`.

**Current workaround**

Using the `end-trunk-dialing-hook` context per tenant in `extensions__90-custom.conf`:

```auto
[T78_end-trunk-dialing-hook]
exten => s,1,NoCDR()
 same => n,Return()

```

Works, but has to be repeated for every tenant prefix.

**Cleanup query**

```sql
DELETE FROM asterisk.cdr
WHERE calltype = '3'
  AND lastapp = 'Hangup'
  AND duration = 0
  AND dstchannel = '';

```
