Follow-Me via Local Channels

Call Handling Asterisk 20+ -- Last reviewed 2026-03-08 call-handling follow-me local-channels gosub callerid Found this useful? Upvote it. ×

Follow-Me via Local Channels

When a call goes unanswered at desk phones, you often want to try cell phones next. This snippet uses Local channels to dial external numbers through a separate context, which lets you control the outbound caller ID independently for each leg. The important part is preserving the original inbound DID as the outbound CID so the cell phone user sees who's actually calling.

The Snippet

The subroutine that rings all cell phones simultaneously:

[followme-all]
exten => s,1,NoOp(Follow Me All - Ringing all cell phones)
 ; Build dial string using Local channels
 ; Each Local channel routes through followme-external context
 same => n,Set(CELL_DIAL_STRING=Local/CELL_100@followme-external&Local/CELL_101@followme-external&Local/CELL_102@followme-external)
 same => n,Dial(${CELL_DIAL_STRING},30,tT)
 same => n,GotoIf($["${DIALSTATUS}" = "ANSWER"]?answered)
 same => n,Set(GOSUB_RETVAL=NOANSWER)
 same => n,Return()
 same => n(answered),Set(GOSUB_RETVAL=ANSWERED)
 same => n,Return()

The external dialing context that handles CID and trunk routing:

[followme-external]
; Extension 100's cell phone
exten => CELL_100,1,NoOp(Follow Me to cell - ext 100)
 same => n,Set(CALLERID(num)=${IF($["${INCOMING_DID}" != ""]?${INCOMING_DID}:${MAIN_DID})})
 same => n,Dial(PJSIP/18025551234@${TRUNK},30,tT)
 same => n,Hangup()

; Extension 101's cell phone
exten => CELL_101,1,NoOp(Follow Me to cell - ext 101)
 same => n,Set(CALLERID(num)=${IF($["${INCOMING_DID}" != ""]?${INCOMING_DID}:${MAIN_DID})})
 same => n,Dial(PJSIP/16035559876@${TRUNK},30,tT)
 same => n,Hangup()

; Extension 102's cell phone
exten => CELL_102,1,NoOp(Follow Me to cell - ext 102)
 same => n,Set(CALLERID(num)=${IF($["${INCOMING_DID}" != ""]?${INCOMING_DID}:${MAIN_DID})})
 same => n,Dial(PJSIP/17815554321@${TRUNK},30,tT)
 same => n,Hangup()

The inbound context sets __INCOMING_DID (double underscore) so it inherits through Local channel hops:

[from-trunk]
exten => 16035551000,1,NoOp(Inbound call from ${CALLERID(num)})
 same => n,Set(__INCOMING_DID=${EXTEN})
 same => n,GotoIfTime(08:00-17:00,mon-fri,*,*?ring-group,s,1)
 same => n,Goto(afterhours,s,1)

How It Works

Local channels create a new channel pair inside Asterisk that connects two dialplan contexts. When you Dial(Local/CELL_100@followme-external), Asterisk creates a mini-call that starts executing at CELL_100 in the followme-external context. This gives you a separate dialplan execution environment where you can set CID, apply different logic, or route through a specific trunk.

Double-underscore inheritance (__INCOMING_DID): Variables prefixed with __ inherit across channel boundaries, including Local channel hops. A single underscore _ only inherits one hop deep. Since the call flow is: inbound trunk -> Local channel -> outbound trunk, we need __ (two hops).

CID preservation: The followme-external context sets CALLERID(num) to the original inbound DID. This means when the cell phone rings, the caller ID shows the company's number, not the PBX's trunk number. If no inbound DID is set (e.g., internal call), it falls back to MAIN_DID.

Why Local Channels Instead of app_followme

app_followme (the FollowMe() application with followme.conf) works well for simple cases. Local channels give you more control:

Calling from After-Hours Context

[afterhours]
exten => s,1,Answer()
 same => n,Wait(1)
 same => n,Playback(after-hours-greeting)
 ; Try desk phones first
 same => n,Dial(PJSIP/100&PJSIP/101&PJSIP/102,20,tTr)
 same => n,GotoIf($["${DIALSTATUS}" = "ANSWER"]?done)
 ; No answer at desk - try cell phones
 same => n,Gosub(followme-all,s,1)
 same => n,GotoIf($["${GOSUB_RETVAL}" = "ANSWERED"]?done)
 ; Still no answer - voicemail
 same => n,VoiceMail(100@default,u)
 same => n(done),Hangup()

User Notes

No notes yet. Be the first to contribute a tip or example.

Contribute a note

Share a tip, gotcha, or practical example. Keep it under 2000 characters. No questions (use the Asterisk community forums for support). Wrap code in backticks.

Moderated before publishing. Email never shown.

Related Snippets