Index: b/main/channel.c
===================================================================
--- a/main/channel.c
+++ b/main/channel.c
@@ -75,6 +75,7 @@
 #include "asterisk/max_forwards.h"
 #include "asterisk/stream.h"
 #include "asterisk/message.h"
+#include "asterisk/cel.h"
 #include "asterisk/rtp_engine.h"
 
 #include "channelstorage.h"
@@ -3560,6 +3561,7 @@ static struct ast_frame *__ast_read(stru
 	struct ast_frame *f = NULL;	/* the return value */
 	int prestate;
 	int cause = 0;
+	enum ast_cel_event_type event_type = 0;
 	struct ast_stream *stream = NULL, *default_stream = NULL;
 
 	/* this function is very long so make sure there is only one return
@@ -3881,6 +3883,10 @@ static struct ast_frame *__ast_read(stru
 				}
 				ast_frfree(f);
 				f = &ast_null_frame;
+			} else if (f->subclass.integer == AST_CONTROL_HOLD) {
+				event_type = AST_CEL_HOLD;
+			} else if (f->subclass.integer == AST_CONTROL_UNHOLD) {
+				event_type = AST_CEL_UNHOLD;
 			} else if (f->subclass.integer == AST_CONTROL_STREAM_TOPOLOGY_REQUEST_CHANGE && dropnondefault) {
 				/* The caller of this function is incapable of handling streams so we don't accept the change request
 				 * and stick to the streams currently on the channel.
@@ -4324,6 +4330,11 @@ done:
 		ast_channel_audiohooks_set(chan, NULL);
 	}
 	ast_channel_unlock(chan);
+
+	if (event_type) {
+		ast_cel_publish_event(chan, event_type, ast_json_null());
+	}
+
 	return f;
 }
 
Index: b/configs/samples/cel.conf.sample
===================================================================
--- a/configs/samples/cel.conf.sample
+++ b/configs/samples/cel.conf.sample
@@ -67,6 +67,8 @@ apps=dial,park
 ;  DTMF             -- A DTMF digit was processed: these events are dispatched at the
 ;                      end, when the button is released and the duration is present in
 ;                      the extra field
+;  HOLD             -- The time a hold control frame was read
+;  UNHOLD           -- The time an unhold control frame was read
 ;
 ; Default value: none
 ;                (Track no events)
Index: b/include/asterisk/cel.h
===================================================================
--- a/include/asterisk/cel.h
+++ b/include/asterisk/cel.h
@@ -84,6 +84,10 @@ enum ast_cel_event_type {
 	AST_CEL_STREAM_END = 20,
 	/*! \brief A DTMF digit was processed */
 	AST_CEL_DTMF = 21,
+	/*! \brief a AST_CONTROL_HOLD frame is read from a channel */
+	AST_CEL_HOLD = 22,
+	/*! \brief a AST_CONTROL_UNHOLD frame is read from a channel */
+	AST_CEL_UNHOLD = 23,
 };
 
 /*!
Index: b/main/cel.c
===================================================================
--- a/main/cel.c
+++ b/main/cel.c
@@ -344,6 +344,8 @@ static const char * const cel_event_type
 	[AST_CEL_STREAM_BEGIN]     = "STREAM_BEGIN",
 	[AST_CEL_STREAM_END]       = "STREAM_END",
 	[AST_CEL_DTMF]             = "DTMF",
+	[AST_CEL_HOLD]             = "HOLD",
+	[AST_CEL_UNHOLD]           = "UNHOLD",
 };
 
 struct cel_backend {
@@ -1327,6 +1329,11 @@ static void cel_generic_cb(
 				event, NULL, NULL);
 			break;
 		}
+	case AST_CEL_HOLD:
+	case AST_CEL_UNHOLD:
+		cel_report_event(obj->snapshot, event_type, stasis_message_timestamp(message),
+			NULL, NULL, NULL);
+		break;
 	default:
 		ast_log(LOG_ERROR, "Unhandled %s event blob\n", ast_cel_get_type_name(event_type));
 		break;
